diff options
645 files changed, 36920 insertions, 19105 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 39c8de0e53d0..b20e829d350f 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -79,7 +79,7 @@ Description: correspond to externally available input one of the named versions may be used. The number must always be specified and unique to allow association with event codes. Units after - application of scale and offset are microvolts. + application of scale and offset are millivolts. What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw KernelVersion: 2.6.35 @@ -90,7 +90,7 @@ Description: physically equivalent inputs when non differential readings are separately available. In differential only parts, then all that is required is a consistent labeling. Units after application - of scale and offset are microvolts. + of scale and offset are millivolts. What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw KernelVersion: 3.2 @@ -537,6 +537,62 @@ Description: value is in raw device units or in processed units (as _raw and _input do on sysfs direct channel read attributes). +What: /sys/.../events/in_accel_x_thresh_rising_hysteresis +What: /sys/.../events/in_accel_x_thresh_falling_hysteresis +What: /sys/.../events/in_accel_x_thresh_either_hysteresis +What: /sys/.../events/in_accel_y_thresh_rising_hysteresis +What: /sys/.../events/in_accel_y_thresh_falling_hysteresis +What: /sys/.../events/in_accel_y_thresh_either_hysteresis +What: /sys/.../events/in_accel_z_thresh_rising_hysteresis +What: /sys/.../events/in_accel_z_thresh_falling_hysteresis +What: /sys/.../events/in_accel_z_thresh_either_hysteresis +What: /sys/.../events/in_anglvel_x_thresh_rising_hysteresis +What: /sys/.../events/in_anglvel_x_thresh_falling_hysteresis +What: /sys/.../events/in_anglvel_x_thresh_either_hysteresis +What: /sys/.../events/in_anglvel_y_thresh_rising_hysteresis +What: /sys/.../events/in_anglvel_y_thresh_falling_hysteresis +What: /sys/.../events/in_anglvel_y_thresh_either_hysteresis +What: /sys/.../events/in_anglvel_z_thresh_rising_hysteresis +What: /sys/.../events/in_anglvel_z_thresh_falling_hysteresis +What: /sys/.../events/in_anglvel_z_thresh_either_hysteresis +What: /sys/.../events/in_magn_x_thresh_rising_hysteresis +What: /sys/.../events/in_magn_x_thresh_falling_hysteresis +What: /sys/.../events/in_magn_x_thresh_either_hysteresis +What: /sys/.../events/in_magn_y_thresh_rising_hysteresis +What: /sys/.../events/in_magn_y_thresh_falling_hysteresis +What: /sys/.../events/in_magn_y_thresh_either_hysteresis +What: /sys/.../events/in_magn_z_thresh_rising_hysteresis +What: /sys/.../events/in_magn_z_thresh_falling_hysteresis +What: /sys/.../events/in_magn_z_thresh_either_hysteresis +What: /sys/.../events/in_voltageY_thresh_rising_hysteresis +What: /sys/.../events/in_voltageY_thresh_falling_hysteresis +What: /sys/.../events/in_voltageY_thresh_either_hysteresis +What: /sys/.../events/in_tempY_thresh_rising_hysteresis +What: /sys/.../events/in_tempY_thresh_falling_hysteresis +What: /sys/.../events/in_tempY_thresh_either_hysteresis +What: /sys/.../events/in_illuminance0_thresh_falling_hysteresis +what: /sys/.../events/in_illuminance0_thresh_rising_hysteresis +what: /sys/.../events/in_illuminance0_thresh_either_hysteresis +what: /sys/.../events/in_proximity0_thresh_falling_hysteresis +what: /sys/.../events/in_proximity0_thresh_rising_hysteresis +what: /sys/.../events/in_proximity0_thresh_either_hysteresis +KernelVersion: 3.13 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the hysteresis of threshold that the device is comparing + against for the events enabled by + <type>Y[_name]_thresh[_(rising|falling)]_hysteresis. + If separate attributes exist for the two directions, but + direction is not specified for this attribute, then a single + hysteresis value applies to both directions. + For falling events the hysteresis is added to the _value attribute for + this event to get the upper threshold for when the event goes back to + normal, for rising events the hysteresis is subtracted from the _value + attribute. E.g. if in_voltage0_raw_thresh_rising_value is set to 1200 + and in_voltage0_raw_thresh_rising_hysteresis is set to 50. The event + will get activated once in_voltage0_raw goes above 1200 and will become + deactived again once the value falls below 1150. + What: /sys/.../events/in_accel_x_raw_roc_rising_value What: /sys/.../events/in_accel_x_raw_roc_falling_value What: /sys/.../events/in_accel_y_raw_roc_rising_value @@ -811,3 +867,14 @@ Description: Writing '1' stores the current device configuration into on-chip EEPROM. After power-up or chip reset the device will automatically load the saved configuration. + +What: /sys/.../iio:deviceX/in_intensity_red_integration_time +What: /sys/.../iio:deviceX/in_intensity_green_integration_time +What: /sys/.../iio:deviceX/in_intensity_blue_integration_time +What: /sys/.../iio:deviceX/in_intensity_clear_integration_time +What: /sys/.../iio:deviceX/in_illuminance_integration_time +KernelVersion: 3.12 +Contact: linux-iio@vger.kernel.org +Description: + This attribute is used to get/set the integration time in + seconds. diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt index 723c205cb10d..d1061469f63d 100644 --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -7,7 +7,6 @@ Required properties: - interrupts: Should contain the IRQ line for the ADC - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this device - - atmel,adc-num-channels: Number of channels available in the ADC - atmel,adc-startup-time: Startup Time of the ADC in microseconds as defined in the datasheet - atmel,adc-vref: Reference voltage in millivolts for the conversions @@ -24,6 +23,13 @@ Optional properties: resolution will be used. - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds + - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this + value is set, then adc driver will enable touch screen + support. + NOTE: when adc touch screen enabled, the adc hardware trigger will be + disabled. Since touch screen will occupied the trigger register. + - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It + make touch detect more precision. Optional trigger Nodes: - Required properties: diff --git a/Documentation/devicetree/bindings/iio/light/cm36651.txt b/Documentation/devicetree/bindings/iio/light/cm36651.txt new file mode 100644 index 000000000000..c03e19db4550 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/cm36651.txt @@ -0,0 +1,26 @@ +* Capella CM36651 I2C Proximity and Color Light sensor + +Required properties: +- compatible: must be "capella,cm36651" +- reg: the I2C address of the device +- interrupts: interrupt-specifier for the sole interrupt + generated by the device +- vled-supply: regulator for the IR LED. IR_LED is a part + of the cm36651 for proximity detection. + As covered in ../../regulator/regulator.txt + +Example: + + i2c_cm36651: i2c-gpio { + /* ... */ + + cm36651@18 { + compatible = "capella,cm36651"; + reg = <0x18>; + interrupt-parent = <&gpx0>; + interrupts = <2 0>; + vled-supply = <&ps_als_reg>; + }; + + /* ... */ + }; diff --git a/Documentation/devicetree/bindings/iio/light/gp2ap020a00f.txt b/Documentation/devicetree/bindings/iio/light/gp2ap020a00f.txt new file mode 100644 index 000000000000..9231c82317ad --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/gp2ap020a00f.txt @@ -0,0 +1,21 @@ +* Sharp GP2AP020A00F I2C Proximity/ALS sensor + +The proximity detector sensor requires power supply +for its built-in led. It is also defined by this binding. + +Required properties: + + - compatible : should be "sharp,gp2ap020a00f" + - reg : the I2C slave address of the light sensor + - interrupts : interrupt specifier for the sole interrupt generated + by the device + - vled-supply : VLED power supply, as covered in ../regulator/regulator.txt + +Example: + +gp2ap020a00f@39 { + compatible = "sharp,gp2ap020a00f"; + reg = <0x39>; + interrupts = <2 0>; + vled-supply = <...>; +}; diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt index 46882058b59b..ee05dc390694 100644 --- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt +++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt @@ -1,7 +1,8 @@ * Freescale i.MX28 LRADC device driver Required properties: -- compatible: Should be "fsl,imx28-lradc" +- compatible: Should be "fsl,imx23-lradc" for i.MX23 SoC and "fsl,imx28-lradc" + for i.MX28 SoC - reg: Address and length of the register set for the device - interrupts: Should contain the LRADC interrupts @@ -9,13 +10,38 @@ Optional properties: - fsl,lradc-touchscreen-wires: Number of wires used to connect the touchscreen to LRADC. Valid value is either 4 or 5. If this property is not present, then the touchscreen is - disabled. + disabled. 5 wires is valid for i.MX28 SoC only. +- fsl,ave-ctrl: number of samples per direction to calculate an average value. + Allowed value is 1 ... 31, default is 4 +- fsl,ave-delay: delay between consecutive samples. Allowed value is + 1 ... 2047. It is used if 'fsl,ave-ctrl' > 1, counts at + 2 kHz and its default is 2 (= 1 ms) +- fsl,settling: delay between plate switch to next sample. Allowed value is + 1 ... 2047. It counts at 2 kHz and its default is + 10 (= 5 ms) -Examples: +Example for i.MX23 SoC: + + lradc@80050000 { + compatible = "fsl,imx23-lradc"; + reg = <0x80050000 0x2000>; + interrupts = <36 37 38 39 40 41 42 43 44>; + status = "okay"; + fsl,lradc-touchscreen-wires = <4>; + fsl,ave-ctrl = <4>; + fsl,ave-delay = <2>; + fsl,settling = <10>; + }; + +Example for i.MX28 SoC: lradc@80050000 { compatible = "fsl,imx28-lradc"; reg = <0x80050000 0x2000>; - interrupts = <10 14 15 16 17 18 19 - 20 21 22 23 24 25>; + interrupts = <10 14 15 16 17 18 19 20 21 22 23 24 25>; + status = "okay"; + fsl,lradc-touchscreen-wires = <5>; + fsl,ave-ctrl = <4>; + fsl,ave-delay = <2>; + fsl,settling = <10>; }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 2956800f0240..04eab45dd148 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -15,6 +15,7 @@ atmel Atmel Corporation avago Avago Technologies bosch Bosch Sensortec GmbH brcm Broadcom Corporation +capella Capella Microsystems, Inc cavium Cavium, Inc. chrp Common Hardware Reference Platform cirrus Cirrus Logic, Inc. diff --git a/MAINTAINERS b/MAINTAINERS index a7c34ef3509d..57508c20eafc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4220,7 +4220,7 @@ S: Maintained F: drivers/media/rc/iguanair.c IIO SUBSYSTEM AND DRIVERS -M: Jonathan Cameron <jic23@cam.ac.uk> +M: Jonathan Cameron <jic23@kernel.org> L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/ @@ -4754,6 +4754,13 @@ S: Maintained F: Documentation/hwmon/k8temp F: drivers/hwmon/k8temp.c +KTAP +M: Jovi Zhangwei <jovi.zhangwei@gmail.com> +W: http://www.ktap.org +L: ktap@freelists.org +S: Maintained +F: drivers/staging/ktap/ + KCONFIG M: Michal Marek <mmarek@suse.cz> L: linux-kbuild@vger.kernel.org @@ -7979,7 +7986,7 @@ S: Maintained F: drivers/staging/media/go7007/ STAGING - INDUSTRIAL IO -M: Jonathan Cameron <jic23@cam.ac.uk> +M: Jonathan Cameron <jic23@kernel.org> L: linux-iio@vger.kernel.org S: Odd Fixes F: drivers/staging/iio/ diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index 28b5ce289662..07caf767d428 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -430,6 +430,7 @@ reg = <0x80050000 0x2000>; interrupts = <36 37 38 39 40 41 42 43 44>; status = "disabled"; + clocks = <&clks 26>; }; spdif@80054000 { diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts index 15715d921d14..aa33393903a8 100644 --- a/arch/arm/boot/dts/imx28-evk.dts +++ b/arch/arm/boot/dts/imx28-evk.dts @@ -183,6 +183,10 @@ lradc@80050000 { status = "okay"; + fsl,lradc-touchscreen-wires = <4>; + fsl,ave-ctrl = <4>; + fsl,ave-delay = <2>; + fsl,settling = <10>; }; i2c0: i2c@80058000 { diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 7363fded95ee..175deefb048b 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -902,6 +902,7 @@ interrupts = <10 14 15 16 17 18 19 20 21 22 23 24 25>; status = "disabled"; + clocks = <&clks 41>; }; spdif: spdif@80054000 { diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h index 048a57f76bd3..c287307b9a3b 100644 --- a/arch/arm/mach-at91/include/mach/at91_adc.h +++ b/arch/arm/mach-at91/include/mach/at91_adc.h @@ -60,14 +60,48 @@ #define AT91_ADC_IER 0x24 /* Interrupt Enable Register */ #define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */ #define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */ +#define AT91_ADC_IER_PEN (1 << 29) +#define AT91_ADC_IER_NOPEN (1 << 30) +#define AT91_ADC_IER_XRDY (1 << 20) +#define AT91_ADC_IER_YRDY (1 << 21) +#define AT91_ADC_IER_PRDY (1 << 22) +#define AT91_ADC_ISR_PENS (1 << 31) #define AT91_ADC_CHR(n) (0x30 + ((n) * 4)) /* Channel Data Register N */ #define AT91_ADC_DATA (0x3ff) #define AT91_ADC_CDR0_9X5 (0x50) /* Channel Data Register 0 for 9X5 */ +#define AT91_ADC_ACR 0x94 /* Analog Control Register */ +#define AT91_ADC_ACR_PENDETSENS (0x3 << 0) /* pull-up resistor */ + +#define AT91_ADC_TSMR 0xB0 +#define AT91_ADC_TSMR_TSMODE (3 << 0) /* Touch Screen Mode */ +#define AT91_ADC_TSMR_TSMODE_NONE (0 << 0) +#define AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS (1 << 0) +#define AT91_ADC_TSMR_TSMODE_4WIRE_PRESS (2 << 0) +#define AT91_ADC_TSMR_TSMODE_5WIRE (3 << 0) +#define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */ +#define AT91_ADC_TSMR_TSAV_(x) ((x) << 4) +#define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */ +#define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */ +#define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28) +#define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */ +#define AT91_ADC_TSMR_PENDET_DIS (0 << 24) /* Pen contact detection disable */ +#define AT91_ADC_TSMR_PENDET_ENA (1 << 24) /* Pen contact detection enable */ + +#define AT91_ADC_TSXPOSR 0xB4 +#define AT91_ADC_TSYPOSR 0xB8 +#define AT91_ADC_TSPRESSR 0xBC + #define AT91_ADC_TRGR_9260 AT91_ADC_MR #define AT91_ADC_TRGR_9G45 0x08 #define AT91_ADC_TRGR_9X5 0xC0 +/* Trigger Register bit field */ +#define AT91_ADC_TRGR_TRGPER (0xffff << 16) +#define AT91_ADC_TRGR_TRGPER_(x) ((x) << 16) +#define AT91_ADC_TRGR_TRGMOD (0x7 << 0) +#define AT91_ADC_TRGR_MOD_PERIOD_TRIG (5 << 0) + #endif diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 10e1581022cf..88fc5aefcd96 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -465,6 +465,39 @@ static int sensor_hub_raw_event(struct hid_device *hdev, return 1; } +int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev) +{ + int ret = 0; + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + + mutex_lock(&data->mutex); + if (!hsdev->ref_cnt) { + ret = hid_hw_open(hsdev->hdev); + if (ret) { + hid_err(hsdev->hdev, "failed to open hid device\n"); + mutex_unlock(&data->mutex); + return ret; + } + } + hsdev->ref_cnt++; + mutex_unlock(&data->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(sensor_hub_device_open); + +void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev) +{ + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + + mutex_lock(&data->mutex); + hsdev->ref_cnt--; + if (!hsdev->ref_cnt) + hid_hw_close(hsdev->hdev); + mutex_unlock(&data->mutex); +} +EXPORT_SYMBOL_GPL(sensor_hub_device_close); + static int sensor_hub_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -506,12 +539,6 @@ static int sensor_hub_probe(struct hid_device *hdev, hid_err(hdev, "hw start failed\n"); return ret; } - ret = hid_hw_open(hdev); - if (ret) { - hid_err(hdev, "failed to open input interrupt pipe\n"); - goto err_stop_hw; - } - INIT_LIST_HEAD(&sd->dyn_callback_list); sd->hid_sensor_client_cnt = 0; report_enum = &hdev->report_enum[HID_INPUT_REPORT]; @@ -520,7 +547,7 @@ static int sensor_hub_probe(struct hid_device *hdev, if (dev_cnt > HID_MAX_PHY_DEVICES) { hid_err(hdev, "Invalid Physical device count\n"); ret = -EINVAL; - goto err_close; + goto err_stop_hw; } sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt * sizeof(struct mfd_cell), @@ -528,7 +555,7 @@ static int sensor_hub_probe(struct hid_device *hdev, if (sd->hid_sensor_hub_client_devs == NULL) { hid_err(hdev, "Failed to allocate memory for mfd cells\n"); ret = -ENOMEM; - goto err_close; + goto err_stop_hw; } list_for_each_entry(report, &report_enum->report_list, list) { hid_dbg(hdev, "Report id:%x\n", report->id); @@ -565,8 +592,6 @@ err_free_names: for (i = 0; i < sd->hid_sensor_client_cnt ; ++i) kfree(sd->hid_sensor_hub_client_devs[i].name); kfree(sd->hid_sensor_hub_client_devs); -err_close: - hid_hw_close(hdev); err_stop_hw: hid_hw_stop(hdev); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 81e3dc260993..28b39283bccf 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -471,13 +471,10 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bma180_data *data = iio_priv(indio_dev); + int64_t time_ns = iio_get_time_ns(); int bit, ret, i = 0; mutex_lock(&data->mutex); - if (indio_dev->scan_timestamp) { - ret = indio_dev->scan_bytes / sizeof(s64) - 1; - ((s64 *)data->buff)[ret] = iio_get_time_ns(); - } for_each_set_bit(bit, indio_dev->buffer->scan_mask, indio_dev->masklength) { @@ -490,7 +487,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) } mutex_unlock(&data->mutex); - iio_push_to_buffers(indio_dev, (u8 *)data->buff); + iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 46d22f3fb1a9..dcda17395c4e 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -182,10 +182,11 @@ static const struct iio_info accel_3d_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -200,7 +201,7 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, accel_state->common_attributes.data_ready); if (accel_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - (u8 *)accel_state->accel_val, + accel_state->accel_val, sizeof(accel_state->accel_val)); return 0; diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index d9b350756f90..a1e642ee13d6 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -32,16 +32,7 @@ int st_accel_trig_set_state(struct iio_trigger *trig, bool state) static int st_accel_buffer_preenable(struct iio_dev *indio_dev) { - int err; - - err = st_sensors_set_enable(indio_dev, true); - if (err < 0) - goto st_accel_set_enable_error; - - err = iio_sw_buffer_preenable(indio_dev); - -st_accel_set_enable_error: - return err; + return st_sensors_set_enable(indio_dev, true); } static int st_accel_buffer_postenable(struct iio_dev *indio_dev) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 1458343f6f3f..38caedc76b98 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -452,8 +452,9 @@ static const struct iio_trigger_ops st_accel_trigger_ops = { int st_accel_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *plat_data) { - int err; struct st_sensor_data *adata = iio_priv(indio_dev); + int irq = adata->get_irq_data_ready(indio_dev); + int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &accel_info; @@ -461,7 +462,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev, err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_accel_sensors), st_accel_sensors); if (err < 0) - goto st_accel_common_probe_error; + return err; adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; adata->multiread_bit = adata->sensor->multi_read_bit; @@ -478,13 +479,13 @@ int st_accel_common_probe(struct iio_dev *indio_dev, err = st_sensors_init_sensor(indio_dev, plat_data); if (err < 0) - goto st_accel_common_probe_error; + return err; - if (adata->get_irq_data_ready(indio_dev) > 0) { - err = st_accel_allocate_ring(indio_dev); - if (err < 0) - goto st_accel_common_probe_error; + err = st_accel_allocate_ring(indio_dev); + if (err < 0) + return err; + if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_ACCEL_TRIGGER_OPS); if (err < 0) @@ -495,15 +496,14 @@ int st_accel_common_probe(struct iio_dev *indio_dev, if (err) goto st_accel_device_register_error; - return err; + return 0; st_accel_device_register_error: - if (adata->get_irq_data_ready(indio_dev) > 0) + if (irq > 0) st_sensors_deallocate_trigger(indio_dev); st_accel_probe_trigger_error: - if (adata->get_irq_data_ready(indio_dev) > 0) - st_accel_deallocate_ring(indio_dev); -st_accel_common_probe_error: + st_accel_deallocate_ring(indio_dev); + return err; } EXPORT_SYMBOL(st_accel_common_probe); @@ -513,10 +513,10 @@ void st_accel_common_remove(struct iio_dev *indio_dev) struct st_sensor_data *adata = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (adata->get_irq_data_ready(indio_dev) > 0) { + if (adata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); - st_accel_deallocate_ring(indio_dev); - } + + st_accel_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_accel_common_remove); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 09371cbc9dc1..2209f28441e9 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -145,6 +145,16 @@ config MCP320X This driver can also be built as a module. If so, the module will be called mcp320x. +config MCP3422 + tristate "Microchip Technology MCP3422/3/4 driver" + depends on I2C + help + Say yes here to build support for Microchip Technology's MCP3422, + MCP3423 or MCP3424 analog to digital converters. + + This driver can also be built as a module. If so, the module will be + called mcp3422. + config NAU7802 tristate "Nuvoton NAU7802 ADC driver" depends on I2C @@ -167,6 +177,8 @@ config TI_ADC081C config TI_AM335X_ADC tristate "TI's AM335X ADC driver" depends on MFD_TI_AM335X_TSCADC + select IIO_BUFFER + select IIO_KFIFO_BUF help Say yes here to build support for Texas Instruments ADC driver which is also a MFD client. diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 33656ef7d1f6..ba9a10a24cd0 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MCP320X) += mcp320x.o +obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 371731df1634..58e945594c7b 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -27,7 +27,7 @@ struct ad7266_state { struct spi_device *spi; struct regulator *reg; - unsigned long vref_uv; + unsigned long vref_mv; struct spi_transfer single_xfer[3]; struct spi_message single_msg; @@ -61,17 +61,7 @@ static int ad7266_powerdown(struct ad7266_state *st) static int ad7266_preenable(struct iio_dev *indio_dev) { struct ad7266_state *st = iio_priv(indio_dev); - int ret; - - ret = ad7266_wakeup(st); - if (ret) - return ret; - - ret = iio_sw_buffer_preenable(indio_dev); - if (ret) - ad7266_powerdown(st); - - return ret; + return ad7266_wakeup(st); } static int ad7266_postdisable(struct iio_dev *indio_dev) @@ -96,9 +86,8 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p) ret = spi_read(st->spi, st->data, 4); if (ret == 0) { - if (indio_dev->scan_timestamp) - ((s64 *)st->data)[1] = pf->timestamp; - iio_push_to_buffers(indio_dev, (u8 *)st->data); + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + pf->timestamp); } iio_trigger_notify_done(indio_dev->trig); @@ -157,7 +146,7 @@ static int ad7266_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long m) { struct ad7266_state *st = iio_priv(indio_dev); - unsigned long scale_uv; + unsigned long scale_mv; int ret; switch (m) { @@ -175,16 +164,15 @@ static int ad7266_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = (st->vref_uv * 100); + scale_mv = st->vref_mv; if (st->mode == AD7266_MODE_DIFF) - scale_uv *= 2; + scale_mv *= 2; if (st->range == AD7266_RANGE_2VREF) - scale_uv *= 2; + scale_mv *= 2; - scale_uv >>= chan->scan_type.realbits; - *val = scale_uv / 100000; - *val2 = (scale_uv % 100000) * 10; - return IIO_VAL_INT_PLUS_MICRO; + *val = scale_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: if (st->range == AD7266_RANGE_2VREF && st->mode != AD7266_MODE_DIFF) @@ -293,7 +281,7 @@ static const struct iio_info ad7266_info = { .driver_module = THIS_MODULE, }; -static unsigned long ad7266_available_scan_masks[] = { +static const unsigned long ad7266_available_scan_masks[] = { 0x003, 0x00c, 0x030, @@ -303,14 +291,14 @@ static unsigned long ad7266_available_scan_masks[] = { 0x000, }; -static unsigned long ad7266_available_scan_masks_diff[] = { +static const unsigned long ad7266_available_scan_masks_diff[] = { 0x003, 0x00c, 0x030, 0x000, }; -static unsigned long ad7266_available_scan_masks_fixed[] = { +static const unsigned long ad7266_available_scan_masks_fixed[] = { 0x003, 0x000, }; @@ -318,7 +306,7 @@ static unsigned long ad7266_available_scan_masks_fixed[] = { struct ad7266_chan_info { const struct iio_chan_spec *channels; unsigned int num_channels; - unsigned long *scan_masks; + const unsigned long *scan_masks; }; #define AD7266_CHAN_INFO_INDEX(_differential, _signed, _fixed) \ @@ -415,10 +403,10 @@ static int ad7266_probe(struct spi_device *spi) if (ret < 0) goto error_disable_reg; - st->vref_uv = ret; + st->vref_mv = ret / 1000; } else { /* Use internal reference */ - st->vref_uv = 2500000; + st->vref_mv = 2500; } if (pdata) { diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 85d1481c312f..2a3b65c74af9 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -159,20 +159,14 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7298_state *st = iio_priv(indio_dev); - s64 time_ns = 0; int b_sent; b_sent = spi_sync(st->spi, &st->ring_msg); if (b_sent) goto done; - if (indio_dev->scan_timestamp) { - time_ns = iio_get_time_ns(); - memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - } - - iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf); + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 6d2b1d8d1a1f..d141d452c3d1 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -64,19 +64,14 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7476_state *st = iio_priv(indio_dev); - s64 time_ns; int b_sent; b_sent = spi_sync(st->spi, &st->msg); if (b_sent < 0) goto done; - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - ((s64 *)st->data)[1] = time_ns; - - iio_push_to_buffers(indio_dev, st->data); + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); @@ -132,10 +127,9 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, } else { scale_uv = st->chip_info->int_vref_uv; } - scale_uv >>= chan->scan_type.realbits; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; + *val = scale_uv / 1000; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index c20203577d2d..c19f8fd1b4b7 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -202,7 +202,6 @@ static int ad7791_read_raw(struct iio_dev *indio_dev, { struct ad7791_state *st = iio_priv(indio_dev); bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR); - unsigned long long scale_pv; switch (info) { case IIO_CHAN_INFO_RAW: @@ -220,23 +219,26 @@ static int ad7791_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: /* The monitor channel uses an internal reference. */ if (chan->address == AD7791_CH_AVDD_MONITOR) { - scale_pv = 5850000000000ULL; + /* + * The signal is attenuated by a factor of 5 and + * compared against a 1.17V internal reference. + */ + *val = 1170 * 5; } else { int voltage_uv; voltage_uv = regulator_get_voltage(st->reg); if (voltage_uv < 0) return voltage_uv; - scale_pv = (unsigned long long)voltage_uv * 1000000; + + *val = voltage_uv / 1000; } if (unipolar) - scale_pv >>= chan->scan_type.realbits; + *val2 = chan->scan_type.realbits; else - scale_pv >>= chan->scan_type.realbits - 1; - *val2 = do_div(scale_pv, 1000000000); - *val = scale_pv; + *val2 = chan->scan_type.realbits - 1; - return IIO_VAL_INT_PLUS_NANO; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 9dd077b78759..acb7f90359a3 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -78,11 +78,6 @@ enum ad7887_supported_device_ids { static int ad7887_ring_preenable(struct iio_dev *indio_dev) { struct ad7887_state *st = iio_priv(indio_dev); - int ret; - - ret = iio_sw_buffer_preenable(indio_dev); - if (ret < 0) - return ret; /* We know this is a single long so can 'cheat' */ switch (*indio_dev->active_scan_mask) { @@ -121,20 +116,14 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7887_state *st = iio_priv(indio_dev); - s64 time_ns; int b_sent; b_sent = spi_sync(st->spi, st->ring_msg); if (b_sent) goto done; - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - memcpy(st->data + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - - iio_push_to_buffers(indio_dev, st->data); + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index 4108dbb28c3d..28732c28e819 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -174,20 +174,14 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7923_state *st = iio_priv(indio_dev); - s64 time_ns = 0; int b_sent; b_sent = spi_sync(st->spi, &st->ring_msg); if (b_sent) goto done; - if (indio_dev->scan_timestamp) { - time_ns = iio_get_time_ns(); - memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - } - - iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf); + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index f0d6335ae087..e6fbd3e70981 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -368,10 +368,6 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) memset(data, 0x00, 16); - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - ((s64 *)data)[1] = pf->timestamp; - reg_size = indio_dev->channels[0].scan_type.realbits + indio_dev->channels[0].scan_type.shift; reg_size = DIV_ROUND_UP(reg_size, 8); @@ -391,7 +387,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) break; } - iio_push_to_buffers(indio_dev, (uint8_t *)data); + iio_push_to_buffers_with_timestamp(indio_dev, data, pf->timestamp); iio_trigger_notify_done(indio_dev->trig); sigma_delta->irq_dis = false; @@ -401,7 +397,6 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) } static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = { - .preenable = &iio_sw_buffer_preenable, .postenable = &ad_sd_buffer_postenable, .predisable = &iio_triggered_buffer_predisable, .postdisable = &ad_sd_buffer_postdisable, diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 0f16b553e063..17df74908db1 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -11,6 +11,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/input.h> #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/kernel.h> @@ -39,10 +40,36 @@ #define at91_adc_writel(st, reg, val) \ (writel_relaxed(val, st->reg_base + reg)) +#define DRIVER_NAME "at91_adc" +#define MAX_POS_BITS 12 + +#define TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */ +#define TOUCH_PEN_DETECT_DEBOUNCE_US 200 + struct at91_adc_caps { + bool has_ts; /* Support touch screen */ + bool has_tsmr; /* only at91sam9x5, sama5d3 have TSMR reg */ + /* + * Numbers of sampling data will be averaged. Can be 0~3. + * Hardware can average (2 ^ ts_filter_average) sample data. + */ + u8 ts_filter_average; + /* Pen Detection input pull-up resistor, can be 0~3 */ + u8 ts_pen_detect_sensitivity; + + /* startup time calculate function */ + u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz); + + u8 num_channels; struct at91_adc_reg_desc registers; }; +enum atmel_adc_ts_type { + ATMEL_ADC_TOUCHSCREEN_NONE = 0, + ATMEL_ADC_TOUCHSCREEN_4WIRE = 4, + ATMEL_ADC_TOUCHSCREEN_5WIRE = 5, +}; + struct at91_adc_state { struct clk *adc_clk; u16 *buffer; @@ -67,6 +94,26 @@ struct at91_adc_state { bool low_res; /* the resolution corresponds to the lowest one */ wait_queue_head_t wq_data_avail; struct at91_adc_caps *caps; + + /* + * Following ADC channels are shared by touchscreen: + * + * CH0 -- Touch screen XP/UL + * CH1 -- Touch screen XM/UR + * CH2 -- Touch screen YP/LL + * CH3 -- Touch screen YM/Sense + * CH4 -- Touch screen LR(5-wire only) + * + * The bitfields below represents the reserved channel in the + * touchscreen mode. + */ +#define CHAN_MASK_TOUCHSCREEN_4WIRE (0xf << 0) +#define CHAN_MASK_TOUCHSCREEN_5WIRE (0x1f << 0) + enum atmel_adc_ts_type touchscreen_type; + struct input_dev *ts_input; + + u16 ts_sample_period_val; + u32 ts_pressure_threshold; }; static irqreturn_t at91_adc_trigger_handler(int irq, void *p) @@ -83,13 +130,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) j++; } - if (idev->scan_timestamp) { - s64 *timestamp = (s64 *)((u8 *)st->buffer + - ALIGN(j, sizeof(s64))); - *timestamp = pf->timestamp; - } - - iio_push_to_buffers(idev, (u8 *)st->buffer); + iio_push_to_buffers_with_timestamp(idev, st->buffer, pf->timestamp); iio_trigger_notify_done(idev->trig); @@ -101,14 +142,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) return IRQ_HANDLED; } -static irqreturn_t at91_adc_eoc_trigger(int irq, void *private) +/* Handler for classic adc channel eoc trigger */ +void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) { - struct iio_dev *idev = private; struct at91_adc_state *st = iio_priv(idev); - u32 status = at91_adc_readl(st, st->registers->status_register); - - if (!(status & st->registers->drdy_mask)) - return IRQ_HANDLED; if (iio_buffer_enabled(idev)) { disable_irq_nosync(irq); @@ -118,6 +155,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private) st->done = true; wake_up_interruptible(&st->wq_data_avail); } +} + +static int at91_ts_sample(struct at91_adc_state *st) +{ + unsigned int xscale, yscale, reg, z1, z2; + unsigned int x, y, pres, xpos, ypos; + unsigned int rxp = 1; + unsigned int factor = 1000; + struct iio_dev *idev = iio_priv_to_dev(st); + + unsigned int xyz_mask_bits = st->res; + unsigned int xyz_mask = (1 << xyz_mask_bits) - 1; + + /* calculate position */ + /* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */ + reg = at91_adc_readl(st, AT91_ADC_TSXPOSR); + xpos = reg & xyz_mask; + x = (xpos << MAX_POS_BITS) - xpos; + xscale = (reg >> 16) & xyz_mask; + if (xscale == 0) { + dev_err(&idev->dev, "Error: xscale == 0!\n"); + return -1; + } + x /= xscale; + + /* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */ + reg = at91_adc_readl(st, AT91_ADC_TSYPOSR); + ypos = reg & xyz_mask; + y = (ypos << MAX_POS_BITS) - ypos; + yscale = (reg >> 16) & xyz_mask; + if (yscale == 0) { + dev_err(&idev->dev, "Error: yscale == 0!\n"); + return -1; + } + y /= yscale; + + /* calculate the pressure */ + reg = at91_adc_readl(st, AT91_ADC_TSPRESSR); + z1 = reg & xyz_mask; + z2 = (reg >> 16) & xyz_mask; + + if (z1 != 0) + pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor) + / factor; + else + pres = st->ts_pressure_threshold; /* no pen contacted */ + + dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n", + xpos, xscale, ypos, yscale, z1, z2, pres); + + if (pres < st->ts_pressure_threshold) { + dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n", + x, y, pres / factor); + input_report_abs(st->ts_input, ABS_X, x); + input_report_abs(st->ts_input, ABS_Y, y); + input_report_abs(st->ts_input, ABS_PRESSURE, pres); + input_report_key(st->ts_input, BTN_TOUCH, 1); + input_sync(st->ts_input); + } else { + dev_dbg(&idev->dev, "pressure too low: not reporting\n"); + } + + return 0; +} + +static irqreturn_t at91_adc_interrupt(int irq, void *private) +{ + struct iio_dev *idev = private; + struct at91_adc_state *st = iio_priv(idev); + u32 status = at91_adc_readl(st, st->registers->status_register); + const uint32_t ts_data_irq_mask = + AT91_ADC_IER_XRDY | + AT91_ADC_IER_YRDY | + AT91_ADC_IER_PRDY; + + if (status & st->registers->drdy_mask) + handle_adc_eoc_trigger(irq, idev); + + if (status & AT91_ADC_IER_PEN) { + at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); + at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN | + ts_data_irq_mask); + /* Set up period trigger for sampling */ + at91_adc_writel(st, st->registers->trigger_register, + AT91_ADC_TRGR_MOD_PERIOD_TRIG | + AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val)); + } else if (status & AT91_ADC_IER_NOPEN) { + at91_adc_writel(st, st->registers->trigger_register, 0); + at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN | + ts_data_irq_mask); + at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); + + input_report_key(st->ts_input, BTN_TOUCH, 0); + input_sync(st->ts_input); + } else if ((status & ts_data_irq_mask) == ts_data_irq_mask) { + /* Now all touchscreen data is ready */ + + if (status & AT91_ADC_ISR_PENS) { + /* validate data by pen contact */ + at91_ts_sample(st); + } else { + /* triggered by event that is no pen contact, just read + * them to clean the interrupt and discard all. + */ + at91_adc_readl(st, AT91_ADC_TSXPOSR); + at91_adc_readl(st, AT91_ADC_TSYPOSR); + at91_adc_readl(st, AT91_ADC_TSPRESSR); + } + } return IRQ_HANDLED; } @@ -127,6 +273,16 @@ static int at91_adc_channel_init(struct iio_dev *idev) struct at91_adc_state *st = iio_priv(idev); struct iio_chan_spec *chan_array, *timestamp; int bit, idx = 0; + unsigned long rsvd_mask = 0; + + /* If touchscreen is enable, then reserve the adc channels */ + if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) + rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE; + else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE) + rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE; + + /* set up the channel mask to reserve touchscreen channels */ + st->channels_mask &= ~rsvd_mask; idev->num_channels = bitmap_weight(&st->channels_mask, st->num_channels) + 1; @@ -279,7 +435,7 @@ static int at91_adc_trigger_init(struct iio_dev *idev) int i, ret; st->trig = devm_kzalloc(&idev->dev, - st->trigger_number * sizeof(st->trig), + st->trigger_number * sizeof(*st->trig), GFP_KERNEL); if (st->trig == NULL) { @@ -372,9 +528,9 @@ static int at91_adc_read_raw(struct iio_dev *idev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = (st->vref_mv * 1000) >> chan->scan_type.realbits; - *val2 = 0; - return IIO_VAL_INT_PLUS_MICRO; + *val = st->vref_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; default: break; } @@ -434,8 +590,80 @@ ret: return ret; } +static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz) +{ + /* + * Number of ticks needed to cover the startup time of the ADC + * as defined in the electrical characteristics of the board, + * divided by 8. The formula thus is : + * Startup Time = (ticks + 1) * 8 / ADC Clock + */ + return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8; +} + +static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz) +{ + /* + * For sama5d3x and at91sam9x5, the formula changes to: + * Startup Time = <lookup_table_value> / ADC Clock + */ + const int startup_lookup[] = { + 0 , 8 , 16 , 24 , + 64 , 80 , 96 , 112, + 512, 576, 640, 704, + 768, 832, 896, 960 + }; + int i, size = ARRAY_SIZE(startup_lookup); + unsigned int ticks; + + ticks = startup_time * adc_clk_khz / 1000; + for (i = 0; i < size; i++) + if (ticks < startup_lookup[i]) + break; + + ticks = i; + if (ticks == size) + /* Reach the end of lookup table */ + ticks = size - 1; + + return ticks; +} + static const struct of_device_id at91_adc_dt_ids[]; +static int at91_adc_probe_dt_ts(struct device_node *node, + struct at91_adc_state *st, struct device *dev) +{ + int ret; + u32 prop; + + ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop); + if (ret) { + dev_info(dev, "ADC Touch screen is disabled.\n"); + return 0; + } + + switch (prop) { + case 4: + case 5: + st->touchscreen_type = prop; + break; + default: + dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop); + return -EINVAL; + } + + prop = 0; + of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop); + st->ts_pressure_threshold = prop; + if (st->ts_pressure_threshold) { + return 0; + } else { + dev_err(dev, "Invalid pressure threshold for the touchscreen\n"); + return -EINVAL; + } +} + static int at91_adc_probe_dt(struct at91_adc_state *st, struct platform_device *pdev) { @@ -460,13 +688,6 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, } st->channels_mask = prop; - if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) { - dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n"); - ret = -EINVAL; - goto error_ret; - } - st->num_channels = prop; - st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode"); if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { @@ -492,6 +713,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, goto error_ret; st->registers = &st->caps->registers; + st->num_channels = st->caps->num_channels; st->trigger_number = of_get_child_count(node); st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number * sizeof(struct at91_adc_trigger), @@ -523,6 +745,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, i++; } + /* Check if touchscreen is supported. */ + if (st->caps->has_ts) + return at91_adc_probe_dt_ts(node, st, &idev->dev); + else + dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n"); + return 0; error_ret: @@ -554,6 +782,114 @@ static const struct iio_info at91_adc_info = { .read_raw = &at91_adc_read_raw, }; +/* Touchscreen related functions */ +static int atmel_ts_open(struct input_dev *dev) +{ + struct at91_adc_state *st = input_get_drvdata(dev); + + at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); + return 0; +} + +static void atmel_ts_close(struct input_dev *dev) +{ + struct at91_adc_state *st = input_get_drvdata(dev); + + at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); +} + +static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz) +{ + u32 reg = 0, pendbc; + int i = 0; + + if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) + reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS; + else + reg = AT91_ADC_TSMR_TSMODE_5WIRE; + + /* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid + * pen detect noise. + * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock + */ + pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1); + + while (pendbc >> ++i) + ; /* Empty! Find the shift offset */ + if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1)))) + pendbc = i; + else + pendbc = i - 1; + + if (st->caps->has_tsmr) { + reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average) + & AT91_ADC_TSMR_TSAV; + reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC; + reg |= AT91_ADC_TSMR_NOTSDMA; + reg |= AT91_ADC_TSMR_PENDET_ENA; + reg |= 0x03 << 8; /* TSFREQ, need bigger than TSAV */ + + at91_adc_writel(st, AT91_ADC_TSMR, reg); + } else { + /* TODO: for 9g45 which has no TSMR */ + } + + /* Change adc internal resistor value for better pen detection, + * default value is 100 kOhm. + * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm + * option only available on ES2 and higher + */ + at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity + & AT91_ADC_ACR_PENDETSENS); + + /* Sample Peroid Time = (TRGPER + 1) / ADCClock */ + st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US * + adc_clk_khz / 1000) - 1, 1); + + return 0; +} + +static int at91_ts_register(struct at91_adc_state *st, + struct platform_device *pdev) +{ + struct input_dev *input; + struct iio_dev *idev = iio_priv_to_dev(st); + int ret; + + input = input_allocate_device(); + if (!input) { + dev_err(&idev->dev, "Failed to allocate TS device!\n"); + return -ENOMEM; + } + + input->name = DRIVER_NAME; + input->id.bustype = BUS_HOST; + input->dev.parent = &pdev->dev; + input->open = atmel_ts_open; + input->close = atmel_ts_close; + + __set_bit(EV_ABS, input->evbit); + __set_bit(EV_KEY, input->evbit); + __set_bit(BTN_TOUCH, input->keybit); + input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0); + input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0); + + st->ts_input = input; + input_set_drvdata(input, st); + + ret = input_register_device(input); + if (ret) + input_free_device(st->ts_input); + + return ret; +} + +static void at91_ts_unregister(struct at91_adc_state *st) +{ + input_unregister_device(st->ts_input); +} + static int at91_adc_probe(struct platform_device *pdev) { unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim; @@ -605,7 +941,7 @@ static int at91_adc_probe(struct platform_device *pdev) at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST); at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); ret = request_irq(st->irq, - at91_adc_eoc_trigger, + at91_adc_interrupt, 0, pdev->dev.driver->name, idev); @@ -650,6 +986,10 @@ static int at91_adc_probe(struct platform_device *pdev) mstrclk = clk_get_rate(st->clk); adc_clk = clk_get_rate(st->adc_clk); adc_clk_khz = adc_clk / 1000; + + dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n", + mstrclk, adc_clk); + prsc = (mstrclk / (2 * adc_clk)) - 1; if (!st->startup_time) { @@ -657,15 +997,9 @@ static int at91_adc_probe(struct platform_device *pdev) ret = -EINVAL; goto error_disable_adc_clk; } + ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz); /* - * Number of ticks needed to cover the startup time of the ADC as - * defined in the electrical characteristics of the board, divided by 8. - * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock - */ - ticks = round_up((st->startup_time * adc_clk_khz / - 1000) - 1, 8) / 8; - /* * a minimal Sample and Hold Time is necessary for the ADC to guarantee * the best converted final value between two channels selection * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock @@ -692,30 +1026,52 @@ static int at91_adc_probe(struct platform_device *pdev) init_waitqueue_head(&st->wq_data_avail); mutex_init(&st->lock); - ret = at91_adc_buffer_init(idev); - if (ret < 0) { - dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); - goto error_disable_adc_clk; - } + /* + * Since touch screen will set trigger register as period trigger. So + * when touch screen is enabled, then we have to disable hardware + * trigger for classic adc. + */ + if (!st->touchscreen_type) { + ret = at91_adc_buffer_init(idev); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); + goto error_disable_adc_clk; + } - ret = at91_adc_trigger_init(idev); - if (ret < 0) { - dev_err(&pdev->dev, "Couldn't setup the triggers.\n"); - goto error_unregister_buffer; + ret = at91_adc_trigger_init(idev); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't setup the triggers.\n"); + at91_adc_buffer_remove(idev); + goto error_disable_adc_clk; + } + } else { + if (!st->caps->has_tsmr) { + dev_err(&pdev->dev, "We don't support non-TSMR adc\n"); + goto error_disable_adc_clk; + } + + ret = at91_ts_register(st, pdev); + if (ret) + goto error_disable_adc_clk; + + at91_ts_hw_init(st, adc_clk_khz); } ret = iio_device_register(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't register the device.\n"); - goto error_remove_triggers; + goto error_iio_device_register; } return 0; -error_remove_triggers: - at91_adc_trigger_remove(idev); -error_unregister_buffer: - at91_adc_buffer_remove(idev); +error_iio_device_register: + if (!st->touchscreen_type) { + at91_adc_trigger_remove(idev); + at91_adc_buffer_remove(idev); + } else { + at91_ts_unregister(st); + } error_disable_adc_clk: clk_disable_unprepare(st->adc_clk); error_disable_clk: @@ -731,8 +1087,12 @@ static int at91_adc_remove(struct platform_device *pdev) struct at91_adc_state *st = iio_priv(idev); iio_device_unregister(idev); - at91_adc_trigger_remove(idev); - at91_adc_buffer_remove(idev); + if (!st->touchscreen_type) { + at91_adc_trigger_remove(idev); + at91_adc_buffer_remove(idev); + } else { + at91_ts_unregister(st); + } clk_disable_unprepare(st->adc_clk); clk_disable_unprepare(st->clk); free_irq(st->irq, idev); @@ -742,6 +1102,8 @@ static int at91_adc_remove(struct platform_device *pdev) #ifdef CONFIG_OF static struct at91_adc_caps at91sam9260_caps = { + .calc_startup_ticks = calc_startup_ticks_9260, + .num_channels = 4, .registers = { .channel_base = AT91_ADC_CHR(0), .drdy_mask = AT91_ADC_DRDY, @@ -753,6 +1115,9 @@ static struct at91_adc_caps at91sam9260_caps = { }; static struct at91_adc_caps at91sam9g45_caps = { + .has_ts = true, + .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */ + .num_channels = 8, .registers = { .channel_base = AT91_ADC_CHR(0), .drdy_mask = AT91_ADC_DRDY, @@ -764,6 +1129,12 @@ static struct at91_adc_caps at91sam9g45_caps = { }; static struct at91_adc_caps at91sam9x5_caps = { + .has_ts = true, + .has_tsmr = true, + .ts_filter_average = 3, + .ts_pen_detect_sensitivity = 2, + .calc_startup_ticks = calc_startup_ticks_9x5, + .num_channels = 12, .registers = { .channel_base = AT91_ADC_CDR0_9X5, .drdy_mask = AT91_ADC_SR_DRDY_9X5, @@ -788,7 +1159,7 @@ static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, .remove = at91_adc_remove, .driver = { - .name = "at91_adc", + .name = DRIVER_NAME, .of_match_table = of_match_ptr(at91_adc_dt_ids), }, }; diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 4fb35d1d7494..cc07b3765fe0 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -397,7 +397,6 @@ static int max1363_read_raw(struct iio_dev *indio_dev, { struct max1363_state *st = iio_priv(indio_dev); int ret; - unsigned long scale_uv; switch (m) { case IIO_CHAN_INFO_RAW: @@ -406,10 +405,9 @@ static int max1363_read_raw(struct iio_dev *indio_dev, return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = st->vref_uv >> st->chip_info->bits; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; + *val = st->vref_uv / 1000; + *val2 = st->chip_info->bits; + return IIO_VAL_FRACTIONAL_LOG2; default: return -EINVAL; } @@ -424,11 +422,21 @@ static const enum max1363_modes max1363_mode_list[] = { d0m1to2m3, d1m0to3m2, }; -#define MAX1363_EV_M \ - (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \ - | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) +static const struct iio_event_spec max1363_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; -#define MAX1363_CHAN_U(num, addr, si, bits, evmask) \ +#define MAX1363_CHAN_U(num, addr, si, bits, ev_spec, num_ev_spec) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -444,11 +452,12 @@ static const enum max1363_modes max1363_mode_list[] = { .endianness = IIO_BE, \ }, \ .scan_index = si, \ - .event_mask = evmask, \ + .event_spec = ev_spec, \ + .num_event_specs = num_ev_spec, \ } /* bipolar channel */ -#define MAX1363_CHAN_B(num, num2, addr, si, bits, evmask) \ +#define MAX1363_CHAN_B(num, num2, addr, si, bits, ev_spec, num_ev_spec) \ { \ .type = IIO_VOLTAGE, \ .differential = 1, \ @@ -466,28 +475,32 @@ static const enum max1363_modes max1363_mode_list[] = { .endianness = IIO_BE, \ }, \ .scan_index = si, \ - .event_mask = evmask, \ + .event_spec = ev_spec, \ + .num_event_specs = num_ev_spec, \ } -#define MAX1363_4X_CHANS(bits, em) { \ - MAX1363_CHAN_U(0, _s0, 0, bits, em), \ - MAX1363_CHAN_U(1, _s1, 1, bits, em), \ - MAX1363_CHAN_U(2, _s2, 2, bits, em), \ - MAX1363_CHAN_U(3, _s3, 3, bits, em), \ - MAX1363_CHAN_B(0, 1, d0m1, 4, bits, em), \ - MAX1363_CHAN_B(2, 3, d2m3, 5, bits, em), \ - MAX1363_CHAN_B(1, 0, d1m0, 6, bits, em), \ - MAX1363_CHAN_B(3, 2, d3m2, 7, bits, em), \ - IIO_CHAN_SOFT_TIMESTAMP(8) \ +#define MAX1363_4X_CHANS(bits, ev_spec, num_ev_spec) { \ + MAX1363_CHAN_U(0, _s0, 0, bits, ev_spec, num_ev_spec), \ + MAX1363_CHAN_U(1, _s1, 1, bits, ev_spec, num_ev_spec), \ + MAX1363_CHAN_U(2, _s2, 2, bits, ev_spec, num_ev_spec), \ + MAX1363_CHAN_U(3, _s3, 3, bits, ev_spec, num_ev_spec), \ + MAX1363_CHAN_B(0, 1, d0m1, 4, bits, ev_spec, num_ev_spec), \ + MAX1363_CHAN_B(2, 3, d2m3, 5, bits, ev_spec, num_ev_spec), \ + MAX1363_CHAN_B(1, 0, d1m0, 6, bits, ev_spec, num_ev_spec), \ + MAX1363_CHAN_B(3, 2, d3m2, 7, bits, ev_spec, num_ev_spec), \ + IIO_CHAN_SOFT_TIMESTAMP(8) \ } -static const struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0); -static const struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0); -static const struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0); +static const struct iio_chan_spec max1036_channels[] = + MAX1363_4X_CHANS(8, NULL, 0); +static const struct iio_chan_spec max1136_channels[] = + MAX1363_4X_CHANS(10, NULL, 0); +static const struct iio_chan_spec max1236_channels[] = + MAX1363_4X_CHANS(12, NULL, 0); static const struct iio_chan_spec max1361_channels[] = - MAX1363_4X_CHANS(10, MAX1363_EV_M); + MAX1363_4X_CHANS(10, max1363_events, ARRAY_SIZE(max1363_events)); static const struct iio_chan_spec max1363_channels[] = - MAX1363_4X_CHANS(12, MAX1363_EV_M); + MAX1363_4X_CHANS(12, max1363_events, ARRAY_SIZE(max1363_events)); /* Applies to max1236, max1237 */ static const enum max1363_modes max1236_mode_list[] = { @@ -511,32 +524,32 @@ static const enum max1363_modes max1238_mode_list[] = { d6m7to8m9, d6m7to10m11, d7m6to9m8, d7m6to11m10, }; -#define MAX1363_12X_CHANS(bits) { \ - MAX1363_CHAN_U(0, _s0, 0, bits, 0), \ - MAX1363_CHAN_U(1, _s1, 1, bits, 0), \ - MAX1363_CHAN_U(2, _s2, 2, bits, 0), \ - MAX1363_CHAN_U(3, _s3, 3, bits, 0), \ - MAX1363_CHAN_U(4, _s4, 4, bits, 0), \ - MAX1363_CHAN_U(5, _s5, 5, bits, 0), \ - MAX1363_CHAN_U(6, _s6, 6, bits, 0), \ - MAX1363_CHAN_U(7, _s7, 7, bits, 0), \ - MAX1363_CHAN_U(8, _s8, 8, bits, 0), \ - MAX1363_CHAN_U(9, _s9, 9, bits, 0), \ - MAX1363_CHAN_U(10, _s10, 10, bits, 0), \ - MAX1363_CHAN_U(11, _s11, 11, bits, 0), \ - MAX1363_CHAN_B(0, 1, d0m1, 12, bits, 0), \ - MAX1363_CHAN_B(2, 3, d2m3, 13, bits, 0), \ - MAX1363_CHAN_B(4, 5, d4m5, 14, bits, 0), \ - MAX1363_CHAN_B(6, 7, d6m7, 15, bits, 0), \ - MAX1363_CHAN_B(8, 9, d8m9, 16, bits, 0), \ - MAX1363_CHAN_B(10, 11, d10m11, 17, bits, 0), \ - MAX1363_CHAN_B(1, 0, d1m0, 18, bits, 0), \ - MAX1363_CHAN_B(3, 2, d3m2, 19, bits, 0), \ - MAX1363_CHAN_B(5, 4, d5m4, 20, bits, 0), \ - MAX1363_CHAN_B(7, 6, d7m6, 21, bits, 0), \ - MAX1363_CHAN_B(9, 8, d9m8, 22, bits, 0), \ - MAX1363_CHAN_B(11, 10, d11m10, 23, bits, 0), \ - IIO_CHAN_SOFT_TIMESTAMP(24) \ +#define MAX1363_12X_CHANS(bits) { \ + MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0), \ + MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0), \ + MAX1363_CHAN_U(2, _s2, 2, bits, NULL, 0), \ + MAX1363_CHAN_U(3, _s3, 3, bits, NULL, 0), \ + MAX1363_CHAN_U(4, _s4, 4, bits, NULL, 0), \ + MAX1363_CHAN_U(5, _s5, 5, bits, NULL, 0), \ + MAX1363_CHAN_U(6, _s6, 6, bits, NULL, 0), \ + MAX1363_CHAN_U(7, _s7, 7, bits, NULL, 0), \ + MAX1363_CHAN_U(8, _s8, 8, bits, NULL, 0), \ + MAX1363_CHAN_U(9, _s9, 9, bits, NULL, 0), \ + MAX1363_CHAN_U(10, _s10, 10, bits, NULL, 0), \ + MAX1363_CHAN_U(11, _s11, 11, bits, NULL, 0), \ + MAX1363_CHAN_B(0, 1, d0m1, 12, bits, NULL, 0), \ + MAX1363_CHAN_B(2, 3, d2m3, 13, bits, NULL, 0), \ + MAX1363_CHAN_B(4, 5, d4m5, 14, bits, NULL, 0), \ + MAX1363_CHAN_B(6, 7, d6m7, 15, bits, NULL, 0), \ + MAX1363_CHAN_B(8, 9, d8m9, 16, bits, NULL, 0), \ + MAX1363_CHAN_B(10, 11, d10m11, 17, bits, NULL, 0), \ + MAX1363_CHAN_B(1, 0, d1m0, 18, bits, NULL, 0), \ + MAX1363_CHAN_B(3, 2, d3m2, 19, bits, NULL, 0), \ + MAX1363_CHAN_B(5, 4, d5m4, 20, bits, NULL, 0), \ + MAX1363_CHAN_B(7, 6, d7m6, 21, bits, NULL, 0), \ + MAX1363_CHAN_B(9, 8, d9m8, 22, bits, NULL, 0), \ + MAX1363_CHAN_B(11, 10, d11m10, 23, bits, NULL, 0), \ + IIO_CHAN_SOFT_TIMESTAMP(24) \ } static const struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8); static const struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10); @@ -561,22 +574,22 @@ static const enum max1363_modes max11608_mode_list[] = { }; #define MAX1363_8X_CHANS(bits) { \ - MAX1363_CHAN_U(0, _s0, 0, bits, 0), \ - MAX1363_CHAN_U(1, _s1, 1, bits, 0), \ - MAX1363_CHAN_U(2, _s2, 2, bits, 0), \ - MAX1363_CHAN_U(3, _s3, 3, bits, 0), \ - MAX1363_CHAN_U(4, _s4, 4, bits, 0), \ - MAX1363_CHAN_U(5, _s5, 5, bits, 0), \ - MAX1363_CHAN_U(6, _s6, 6, bits, 0), \ - MAX1363_CHAN_U(7, _s7, 7, bits, 0), \ - MAX1363_CHAN_B(0, 1, d0m1, 8, bits, 0), \ - MAX1363_CHAN_B(2, 3, d2m3, 9, bits, 0), \ - MAX1363_CHAN_B(4, 5, d4m5, 10, bits, 0), \ - MAX1363_CHAN_B(6, 7, d6m7, 11, bits, 0), \ - MAX1363_CHAN_B(1, 0, d1m0, 12, bits, 0), \ - MAX1363_CHAN_B(3, 2, d3m2, 13, bits, 0), \ - MAX1363_CHAN_B(5, 4, d5m4, 14, bits, 0), \ - MAX1363_CHAN_B(7, 6, d7m6, 15, bits, 0), \ + MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0), \ + MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0), \ + MAX1363_CHAN_U(2, _s2, 2, bits, NULL, 0), \ + MAX1363_CHAN_U(3, _s3, 3, bits, NULL, 0), \ + MAX1363_CHAN_U(4, _s4, 4, bits, NULL, 0), \ + MAX1363_CHAN_U(5, _s5, 5, bits, NULL, 0), \ + MAX1363_CHAN_U(6, _s6, 6, bits, NULL, 0), \ + MAX1363_CHAN_U(7, _s7, 7, bits, NULL, 0), \ + MAX1363_CHAN_B(0, 1, d0m1, 8, bits, NULL, 0), \ + MAX1363_CHAN_B(2, 3, d2m3, 9, bits, NULL, 0), \ + MAX1363_CHAN_B(4, 5, d4m5, 10, bits, NULL, 0), \ + MAX1363_CHAN_B(6, 7, d6m7, 11, bits, NULL, 0), \ + MAX1363_CHAN_B(1, 0, d1m0, 12, bits, NULL, 0), \ + MAX1363_CHAN_B(3, 2, d3m2, 13, bits, NULL, 0), \ + MAX1363_CHAN_B(5, 4, d5m4, 14, bits, NULL, 0), \ + MAX1363_CHAN_B(7, 6, d7m6, 15, bits, NULL, 0), \ IIO_CHAN_SOFT_TIMESTAMP(16) \ } static const struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8); @@ -588,10 +601,10 @@ static const enum max1363_modes max11644_mode_list[] = { }; #define MAX1363_2X_CHANS(bits) { \ - MAX1363_CHAN_U(0, _s0, 0, bits, 0), \ - MAX1363_CHAN_U(1, _s1, 1, bits, 0), \ - MAX1363_CHAN_B(0, 1, d0m1, 2, bits, 0), \ - MAX1363_CHAN_B(1, 0, d1m0, 3, bits, 0), \ + MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0), \ + MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0), \ + MAX1363_CHAN_B(0, 1, d0m1, 2, bits, NULL, 0), \ + MAX1363_CHAN_B(1, 0, d1m0, 3, bits, NULL, 0), \ IIO_CHAN_SOFT_TIMESTAMP(4) \ } @@ -686,20 +699,22 @@ static IIO_CONST_ATTR(sampling_frequency_available, "133000 665000 33300 16600 8300 4200 2000 1000"); static int max1363_read_thresh(struct iio_dev *indio_dev, - u64 event_code, - int *val) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, int *val, + int *val2) { struct max1363_state *st = iio_priv(indio_dev); - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) - *val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)]; + if (dir == IIO_EV_DIR_FALLING) + *val = st->thresh_low[chan->channel]; else - *val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)]; - return 0; + *val = st->thresh_high[chan->channel]; + return IIO_VAL_INT; } static int max1363_write_thresh(struct iio_dev *indio_dev, - u64 event_code, - int val) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, int val, + int val2) { struct max1363_state *st = iio_priv(indio_dev); /* make it handle signed correctly as well */ @@ -714,13 +729,15 @@ static int max1363_write_thresh(struct iio_dev *indio_dev, break; } - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + switch (dir) { case IIO_EV_DIR_FALLING: - st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val; + st->thresh_low[chan->channel] = val; break; case IIO_EV_DIR_RISING: - st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val; + st->thresh_high[chan->channel] = val; break; + default: + return -EINVAL; } return 0; @@ -765,14 +782,15 @@ static irqreturn_t max1363_event_handler(int irq, void *private) } static int max1363_read_event_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) { struct max1363_state *st = iio_priv(indio_dev); int val; - int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code); + int number = chan->channel; mutex_lock(&indio_dev->mlock); - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) + if (dir == IIO_EV_DIR_FALLING) val = (1 << number) & st->mask_low; else val = (1 << number) & st->mask_high; @@ -917,17 +935,17 @@ error_ret: } static int max1363_write_event_config(struct iio_dev *indio_dev, - u64 event_code, - int state) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) { int ret = 0; struct max1363_state *st = iio_priv(indio_dev); u16 unifiedmask; - int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code); + int number = chan->channel; mutex_lock(&indio_dev->mlock); unifiedmask = st->mask_low | st->mask_high; - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) { + if (dir == IIO_EV_DIR_FALLING) { if (state == 0) st->mask_low &= ~(1 << number); @@ -995,10 +1013,10 @@ static const struct iio_info max1238_info = { }; static const struct iio_info max1363_info = { - .read_event_value = &max1363_read_thresh, - .write_event_value = &max1363_write_thresh, - .read_event_config = &max1363_read_event_config, - .write_event_config = &max1363_write_event_config, + .read_event_value_new = &max1363_read_thresh, + .write_event_value_new = &max1363_write_thresh, + .read_event_config_new = &max1363_read_event_config, + .write_event_config_new = &max1363_write_event_config, .read_raw = &max1363_read_raw, .update_scan_mode = &max1363_update_scan_mode, .driver_module = THIS_MODULE, @@ -1436,7 +1454,6 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct max1363_state *st = iio_priv(indio_dev); - s64 time_ns; __u8 *rxbuf; int b_sent; size_t d_size; @@ -1470,11 +1487,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) if (b_sent < 0) goto done_free; - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); - iio_push_to_buffers(indio_dev, rxbuf); + iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, iio_get_time_ns()); done_free: kfree(rxbuf); @@ -1484,12 +1497,6 @@ done: return IRQ_HANDLED; } -static const struct iio_buffer_setup_ops max1363_buffered_setup_ops = { - .postenable = &iio_triggered_buffer_postenable, - .preenable = &iio_sw_buffer_preenable, - .predisable = &iio_triggered_buffer_predisable, -}; - static int max1363_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1559,7 +1566,7 @@ static int max1363_probe(struct i2c_client *client, goto error_disable_reg; ret = iio_triggered_buffer_setup(indio_dev, NULL, - &max1363_trigger_handler, &max1363_buffered_setup_ops); + &max1363_trigger_handler, NULL); if (ret) goto error_disable_reg; diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c new file mode 100644 index 000000000000..12948325431c --- /dev/null +++ b/drivers/iio/adc/mcp3422.c @@ -0,0 +1,410 @@ +/* + * mcp3422.c - driver for the Microchip mcp3422/3/4 chip family + * + * Copyright (C) 2013, Angelo Compagnucci + * Author: Angelo Compagnucci <angelo.compagnucci@gmail.com> + * + * Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf + * + * This driver exports the value of analog input voltage to sysfs, the + * voltage unit is nV. + * + * 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/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/sysfs.h> +#include <linux/of.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +/* Masks */ +#define MCP3422_CHANNEL_MASK 0x60 +#define MCP3422_PGA_MASK 0x03 +#define MCP3422_SRATE_MASK 0x0C +#define MCP3422_SRATE_240 0x0 +#define MCP3422_SRATE_60 0x1 +#define MCP3422_SRATE_15 0x2 +#define MCP3422_SRATE_3 0x3 +#define MCP3422_PGA_1 0 +#define MCP3422_PGA_2 1 +#define MCP3422_PGA_4 2 +#define MCP3422_PGA_8 3 +#define MCP3422_CONT_SAMPLING 0x10 + +#define MCP3422_CHANNEL(config) (((config) & MCP3422_CHANNEL_MASK) >> 5) +#define MCP3422_PGA(config) ((config) & MCP3422_PGA_MASK) +#define MCP3422_SAMPLE_RATE(config) (((config) & MCP3422_SRATE_MASK) >> 2) + +#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK) +#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK) +#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK) + +#define MCP3422_CHAN(_index) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ + | BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + } + +/* LSB is in nV to eliminate floating point */ +static const u32 rates_to_lsb[] = {1000000, 250000, 62500, 15625}; + +/* + * scales calculated as: + * rates_to_lsb[sample_rate] / (1 << pga); + * pga is 1 for 0, 2 + */ + +static const int mcp3422_scales[4][4] = { + { 1000000, 250000, 62500, 15625 }, + { 500000 , 125000, 31250, 7812 }, + { 250000 , 62500 , 15625, 3906 }, + { 125000 , 31250 , 7812 , 1953 } }; + +/* Constant msleep times for data acquisitions */ +static const int mcp3422_read_times[4] = { + [MCP3422_SRATE_240] = 1000 / 240, + [MCP3422_SRATE_60] = 1000 / 60, + [MCP3422_SRATE_15] = 1000 / 15, + [MCP3422_SRATE_3] = 1000 / 3 }; + +/* sample rates to integer conversion table */ +static const int mcp3422_sample_rates[4] = { + [MCP3422_SRATE_240] = 240, + [MCP3422_SRATE_60] = 60, + [MCP3422_SRATE_15] = 15, + [MCP3422_SRATE_3] = 3 }; + +/* sample rates to sign extension table */ +static const int mcp3422_sign_extend[4] = { + [MCP3422_SRATE_240] = 12, + [MCP3422_SRATE_60] = 14, + [MCP3422_SRATE_15] = 16, + [MCP3422_SRATE_3] = 18 }; + +/* Client data (each client gets its own) */ +struct mcp3422 { + struct i2c_client *i2c; + u8 config; + u8 pga[4]; + struct mutex lock; +}; + +static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig) +{ + int ret; + + mutex_lock(&adc->lock); + + ret = i2c_master_send(adc->i2c, &newconfig, 1); + if (ret > 0) { + adc->config = newconfig; + ret = 0; + } + + mutex_unlock(&adc->lock); + + return ret; +} + +static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config) +{ + int ret = 0; + u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + u8 buf[4] = {0, 0, 0, 0}; + u32 temp; + + if (sample_rate == MCP3422_SRATE_3) { + ret = i2c_master_recv(adc->i2c, buf, 4); + temp = buf[0] << 16 | buf[1] << 8 | buf[2]; + *config = buf[3]; + } else { + ret = i2c_master_recv(adc->i2c, buf, 3); + temp = buf[0] << 8 | buf[1]; + *config = buf[2]; + } + + *value = sign_extend32(temp, mcp3422_sign_extend[sample_rate]); + + return ret; +} + +static int mcp3422_read_channel(struct mcp3422 *adc, + struct iio_chan_spec const *channel, int *value) +{ + int ret; + u8 config; + u8 req_channel = channel->channel; + + if (req_channel != MCP3422_CHANNEL(adc->config)) { + config = adc->config; + config &= ~MCP3422_CHANNEL_MASK; + config |= MCP3422_CHANNEL_VALUE(req_channel); + config &= ~MCP3422_PGA_MASK; + config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + ret = mcp3422_update_config(adc, config); + if (ret < 0) + return ret; + msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]); + } + + return mcp3422_read(adc, value, &config); +} + +static int mcp3422_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *channel, int *val1, + int *val2, long mask) +{ + struct mcp3422 *adc = iio_priv(iio); + int err; + + u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + u8 pga = MCP3422_PGA(adc->config); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = mcp3422_read_channel(adc, channel, val1); + if (err < 0) + return -EINVAL; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + + *val1 = 0; + *val2 = mcp3422_scales[sample_rate][pga]; + return IIO_VAL_INT_PLUS_NANO; + + case IIO_CHAN_INFO_SAMP_FREQ: + *val1 = mcp3422_sample_rates[MCP3422_SAMPLE_RATE(adc->config)]; + return IIO_VAL_INT; + + default: + break; + } + + return -EINVAL; +} + +static int mcp3422_write_raw(struct iio_dev *iio, + struct iio_chan_spec const *channel, int val1, + int val2, long mask) +{ + struct mcp3422 *adc = iio_priv(iio); + u8 temp; + u8 config = adc->config; + u8 req_channel = channel->channel; + u8 sample_rate = MCP3422_SAMPLE_RATE(config); + u8 i; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (val1 != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(mcp3422_scales[0]); i++) { + if (val2 == mcp3422_scales[sample_rate][i]) { + adc->pga[req_channel] = i; + + config &= ~MCP3422_CHANNEL_MASK; + config |= MCP3422_CHANNEL_VALUE(req_channel); + config &= ~MCP3422_PGA_MASK; + config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + + return mcp3422_update_config(adc, config); + } + } + return -EINVAL; + + case IIO_CHAN_INFO_SAMP_FREQ: + switch (val1) { + case 240: + temp = MCP3422_SRATE_240; + break; + case 60: + temp = MCP3422_SRATE_60; + break; + case 15: + temp = MCP3422_SRATE_15; + break; + case 3: + temp = MCP3422_SRATE_3; + break; + default: + return -EINVAL; + } + + config &= ~MCP3422_CHANNEL_MASK; + config |= MCP3422_CHANNEL_VALUE(req_channel); + config &= ~MCP3422_SRATE_MASK; + config |= MCP3422_SAMPLE_RATE_VALUE(temp); + + return mcp3422_update_config(adc, config); + + default: + break; + } + + return -EINVAL; +} + +static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static ssize_t mcp3422_show_scales(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); + u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + + return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", + mcp3422_scales[sample_rate][0], + mcp3422_scales[sample_rate][1], + mcp3422_scales[sample_rate][2], + mcp3422_scales[sample_rate][3]); +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("240 60 15 3"); +static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, + mcp3422_show_scales, NULL, 0); + +static struct attribute *mcp3422_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group mcp3422_attribute_group = { + .attrs = mcp3422_attributes, +}; + +static const struct iio_chan_spec mcp3422_channels[] = { + MCP3422_CHAN(0), + MCP3422_CHAN(1), +}; + +static const struct iio_chan_spec mcp3424_channels[] = { + MCP3422_CHAN(0), + MCP3422_CHAN(1), + MCP3422_CHAN(2), + MCP3422_CHAN(3), +}; + +static const struct iio_info mcp3422_info = { + .read_raw = mcp3422_read_raw, + .write_raw = mcp3422_write_raw, + .write_raw_get_fmt = mcp3422_write_raw_get_fmt, + .attrs = &mcp3422_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int mcp3422_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct mcp3422 *adc; + int err; + u8 config; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->i2c = client; + + mutex_init(&adc->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->name = dev_name(&client->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mcp3422_info; + + switch ((unsigned int)(id->driver_data)) { + case 2: + case 3: + indio_dev->channels = mcp3422_channels; + indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels); + break; + case 4: + indio_dev->channels = mcp3424_channels; + indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels); + break; + } + + /* meaningful default configuration */ + config = (MCP3422_CONT_SAMPLING + | MCP3422_CHANNEL_VALUE(1) + | MCP3422_PGA_VALUE(MCP3422_PGA_1) + | MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240)); + mcp3422_update_config(adc, config); + + err = iio_device_register(indio_dev); + if (err < 0) + return err; + + i2c_set_clientdata(client, indio_dev); + + return 0; +} + +static int mcp3422_remove(struct i2c_client *client) +{ + iio_device_unregister(i2c_get_clientdata(client)); + return 0; +} + +static const struct i2c_device_id mcp3422_id[] = { + { "mcp3422", 2 }, + { "mcp3423", 3 }, + { "mcp3424", 4 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mcp3422_id); + +#ifdef CONFIG_OF +static const struct of_device_id mcp3422_of_match[] = { + { .compatible = "mcp3422" }, + { } +}; +MODULE_DEVICE_TABLE(of, mcp3422_of_match); +#endif + +static struct i2c_driver mcp3422_driver = { + .driver = { + .name = "mcp3422", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mcp3422_of_match), + }, + .probe = mcp3422_probe, + .remove = mcp3422_remove, + .id_table = mcp3422_id, +}; +module_i2c_driver(mcp3422_driver); + +MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>"); +MODULE_DESCRIPTION("Microchip mcp3422/3/4 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index bdf03468f3b8..adff9cbbcbc4 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/wait.h> #include <linux/log2.h> +#include <linux/of.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index ee5f72bffe5a..b3a82b4d1a75 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -9,6 +9,7 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/iio/iio.h> #include <linux/regulator/consumer.h> diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index a952538a1a8b..ef54d8a588d2 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -28,12 +28,16 @@ #include <linux/iio/driver.h> #include <linux/mfd/ti_am335x_tscadc.h> +#include <linux/iio/buffer.h> +#include <linux/iio/kfifo_buf.h> struct tiadc_device { struct ti_tscadc_dev *mfd_tscadc; int channels; u8 channel_line[8]; u8 channel_step[8]; + int buffer_en_ch_steps; + u16 data[8]; }; static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) @@ -56,8 +60,14 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev) return step_en; } -static void tiadc_step_config(struct tiadc_device *adc_dev) +static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) { + return 1 << adc_dev->channel_step[chan]; +} + +static void tiadc_step_config(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); unsigned int stepconfig; int i, steps; @@ -72,7 +82,11 @@ static void tiadc_step_config(struct tiadc_device *adc_dev) */ steps = TOTAL_STEPS - adc_dev->channels; - stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1; + if (iio_buffer_enabled(indio_dev)) + stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1 + | STEPCONFIG_MODE_SWCNT; + else + stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1; for (i = 0; i < adc_dev->channels; i++) { int chan; @@ -85,9 +99,175 @@ static void tiadc_step_config(struct tiadc_device *adc_dev) adc_dev->channel_step[i] = steps; steps++; } +} + +static irqreturn_t tiadc_irq_h(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct tiadc_device *adc_dev = iio_priv(indio_dev); + unsigned int status, config; + status = tiadc_readl(adc_dev, REG_IRQSTATUS); + + /* + * ADC and touchscreen share the IRQ line. + * FIFO0 interrupts are used by TSC. Handle FIFO1 IRQs here only + */ + if (status & IRQENB_FIFO1OVRRUN) { + /* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */ + config = tiadc_readl(adc_dev, REG_CTRL); + config &= ~(CNTRLREG_TSCSSENB); + tiadc_writel(adc_dev, REG_CTRL, config); + tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN + | IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES); + tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB)); + return IRQ_HANDLED; + } else if (status & IRQENB_FIFO1THRES) { + /* Disable irq and wake worker thread */ + tiadc_writel(adc_dev, REG_IRQCLR, IRQENB_FIFO1THRES); + return IRQ_WAKE_THREAD; + } + + return IRQ_NONE; +} + +static irqreturn_t tiadc_worker_h(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct tiadc_device *adc_dev = iio_priv(indio_dev); + int i, k, fifo1count, read; + u16 *data = adc_dev->data; + + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); + for (k = 0; k < fifo1count; k = k + i) { + for (i = 0; i < (indio_dev->scan_bytes)/2; i++) { + read = tiadc_readl(adc_dev, REG_FIFO1); + data[i] = read & FIFOREAD_DATA_MASK; + } + iio_push_to_buffers(indio_dev, (u8 *) data); + } + + tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES); + tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); + return IRQ_HANDLED; } +static int tiadc_buffer_preenable(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); + int i, fifo1count, read; + + tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | + IRQENB_FIFO1OVRRUN | + IRQENB_FIFO1UNDRFLW)); + + /* Flush FIFO. Needed in corner cases in simultaneous tsc/adc use */ + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); + for (i = 0; i < fifo1count; i++) + read = tiadc_readl(adc_dev, REG_FIFO1); + + return 0; +} + +static int tiadc_buffer_postenable(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); + struct iio_buffer *buffer = indio_dev->buffer; + unsigned int enb = 0; + u8 bit; + + tiadc_step_config(indio_dev); + for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels) + enb |= (get_adc_step_bit(adc_dev, bit) << 1); + adc_dev->buffer_en_ch_steps = enb; + + am335x_tsc_se_set(adc_dev->mfd_tscadc, enb); + + tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES + | IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW); + tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES + | IRQENB_FIFO1OVRRUN); + + return 0; +} + +static int tiadc_buffer_predisable(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); + int fifo1count, i, read; + + tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | + IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW)); + am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps); + + /* Flush FIFO of leftover data in the time it takes to disable adc */ + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); + for (i = 0; i < fifo1count; i++) + read = tiadc_readl(adc_dev, REG_FIFO1); + + return 0; +} + +static int tiadc_buffer_postdisable(struct iio_dev *indio_dev) +{ + tiadc_step_config(indio_dev); + + return 0; +} + +static const struct iio_buffer_setup_ops tiadc_buffer_setup_ops = { + .preenable = &tiadc_buffer_preenable, + .postenable = &tiadc_buffer_postenable, + .predisable = &tiadc_buffer_predisable, + .postdisable = &tiadc_buffer_postdisable, +}; + +static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev, + irqreturn_t (*pollfunc_bh)(int irq, void *p), + irqreturn_t (*pollfunc_th)(int irq, void *p), + int irq, + unsigned long flags, + const struct iio_buffer_setup_ops *setup_ops) +{ + int ret; + + indio_dev->buffer = iio_kfifo_allocate(indio_dev); + if (!indio_dev->buffer) + return -ENOMEM; + + ret = request_threaded_irq(irq, pollfunc_th, pollfunc_bh, + flags, indio_dev->name, indio_dev); + if (ret) + goto error_kfifo_free; + + indio_dev->setup_ops = setup_ops; + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + + ret = iio_buffer_register(indio_dev, + indio_dev->channels, + indio_dev->num_channels); + if (ret) + goto error_free_irq; + + return 0; + +error_free_irq: + free_irq(irq, indio_dev); +error_kfifo_free: + iio_kfifo_free(indio_dev->buffer); + return ret; +} + +static void tiadc_iio_buffered_hardware_remove(struct iio_dev *indio_dev) +{ + struct tiadc_device *adc_dev = iio_priv(indio_dev); + + free_irq(adc_dev->mfd_tscadc->irq, indio_dev); + iio_kfifo_free(indio_dev->buffer); + iio_buffer_unregister(indio_dev); +} + + static const char * const chan_name_ain[] = { "AIN0", "AIN1", @@ -120,9 +300,10 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) chan->channel = adc_dev->channel_line[i]; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); chan->datasheet_name = chan_name_ain[chan->channel]; + chan->scan_index = i; chan->scan_type.sign = 'u'; chan->scan_type.realbits = 12; - chan->scan_type.storagebits = 32; + chan->scan_type.storagebits = 16; } indio_dev->channels = chan_array; @@ -142,11 +323,14 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, struct tiadc_device *adc_dev = iio_priv(indio_dev); int i, map_val; unsigned int fifo1count, read, stepid; - u32 step = UINT_MAX; bool found = false; u32 step_en; unsigned long timeout = jiffies + usecs_to_jiffies (IDLE_TIMEOUT * adc_dev->channels); + + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + step_en = get_adc_step_mask(adc_dev); am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en); @@ -168,15 +352,6 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, * Hence we need to flush out this data. */ - for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) { - if (chan->channel == adc_dev->channel_line[i]) { - step = adc_dev->channel_step[i]; - break; - } - } - if (WARN_ON_ONCE(step == UINT_MAX)) - return -EINVAL; - fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); for (i = 0; i < fifo1count; i++) { read = tiadc_readl(adc_dev, REG_FIFO1); @@ -186,7 +361,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, if (stepid == map_val) { read = read & FIFOREAD_DATA_MASK; found = true; - *val = read; + *val = (u16) read; } } @@ -237,20 +412,33 @@ static int tiadc_probe(struct platform_device *pdev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &tiadc_info; - tiadc_step_config(adc_dev); + tiadc_step_config(indio_dev); + tiadc_writel(adc_dev, REG_FIFO1THR, FIFO1_THRESHOLD); err = tiadc_channel_init(indio_dev, adc_dev->channels); if (err < 0) return err; - err = iio_device_register(indio_dev); + err = tiadc_iio_buffered_hardware_setup(indio_dev, + &tiadc_worker_h, + &tiadc_irq_h, + adc_dev->mfd_tscadc->irq, + IRQF_SHARED, + &tiadc_buffer_setup_ops); + if (err) goto err_free_channels; + err = iio_device_register(indio_dev); + if (err) + goto err_buffer_unregister; + platform_set_drvdata(pdev, indio_dev); return 0; +err_buffer_unregister: + tiadc_iio_buffered_hardware_remove(indio_dev); err_free_channels: tiadc_channels_remove(indio_dev); return err; @@ -263,6 +451,7 @@ static int tiadc_remove(struct platform_device *pdev) u32 step_en; iio_device_unregister(indio_dev); + tiadc_iio_buffered_hardware_remove(indio_dev); tiadc_channels_remove(indio_dev); step_en = get_adc_step_mask(adc_dev); @@ -301,7 +490,7 @@ static int tiadc_resume(struct device *dev) restore &= ~(CNTRLREG_POWERDOWN); tiadc_writel(adc_dev, REG_CTRL, restore); - tiadc_step_config(adc_dev); + tiadc_step_config(indio_dev); return 0; } diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c index 415f3c6efd72..2d9c6f8c06db 100644 --- a/drivers/iio/buffer_cb.c +++ b/drivers/iio/buffer_cb.c @@ -7,26 +7,36 @@ struct iio_cb_buffer { struct iio_buffer buffer; - int (*cb)(u8 *data, void *private); + int (*cb)(const void *data, void *private); void *private; struct iio_channel *channels; }; -static int iio_buffer_cb_store_to(struct iio_buffer *buffer, u8 *data) +static struct iio_cb_buffer *buffer_to_cb_buffer(struct iio_buffer *buffer) { - struct iio_cb_buffer *cb_buff = container_of(buffer, - struct iio_cb_buffer, - buffer); + return container_of(buffer, struct iio_cb_buffer, buffer); +} +static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data) +{ + struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer); return cb_buff->cb(data, cb_buff->private); } -static struct iio_buffer_access_funcs iio_cb_access = { +static void iio_buffer_cb_release(struct iio_buffer *buffer) +{ + struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer); + kfree(cb_buff->buffer.scan_mask); + kfree(cb_buff); +} + +static const struct iio_buffer_access_funcs iio_cb_access = { .store_to = &iio_buffer_cb_store_to, + .release = &iio_buffer_cb_release, }; struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, - int (*cb)(u8 *data, + int (*cb)(const void *data, void *private), void *private) { @@ -104,9 +114,8 @@ EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb); void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buff) { - kfree(cb_buff->buffer.scan_mask); iio_channel_release_all(cb_buff->channels); - kfree(cb_buff); + iio_buffer_put(&cb_buff->buffer); } EXPORT_SYMBOL_GPL(iio_channel_release_all_cb); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 87419c41b991..b6e77e0fc420 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -34,6 +34,12 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, struct hid_sensor_common *st = iio_trigger_get_drvdata(trig); int state_val; + if (state) { + if (sensor_hub_device_open(st->hsdev)) + return -EIO; + } else + sensor_hub_device_close(st->hsdev); + state_val = state ? 1 : 0; if (IS_ENABLED(CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS)) ++state_val; diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 71a2c5f63b9c..1665c8e4b62b 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -113,11 +113,8 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) if (len < 0) goto st_sensors_get_buffer_element_error; - if (indio_dev->scan_timestamp) - *(s64 *)((u8 *)sdata->buffer_data + - ALIGN(len, sizeof(s64))) = pf->timestamp; - - iio_push_to_buffers(indio_dev, sdata->buffer_data); + iio_push_to_buffers_with_timestamp(indio_dev, sdata->buffer_data, + pf->timestamp); st_sensors_get_buffer_element_error: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 965ee22d3ac8..7ba1ef270213 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -198,21 +198,17 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) } EXPORT_SYMBOL(st_sensors_set_axis_enable); -int st_sensors_init_sensor(struct iio_dev *indio_dev, - struct st_sensors_platform_data *pdata) +static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, + struct st_sensors_platform_data *pdata) { - int err; struct st_sensor_data *sdata = iio_priv(indio_dev); - mutex_init(&sdata->tb.buf_lock); - switch (pdata->drdy_int_pin) { case 1: if (sdata->sensor->drdy_irq.mask_int1 == 0) { dev_err(&indio_dev->dev, "DRDY on INT1 not available.\n"); - err = -EINVAL; - goto init_error; + return -EINVAL; } sdata->drdy_int_pin = 1; break; @@ -220,39 +216,53 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, if (sdata->sensor->drdy_irq.mask_int2 == 0) { dev_err(&indio_dev->dev, "DRDY on INT2 not available.\n"); - err = -EINVAL; - goto init_error; + return -EINVAL; } sdata->drdy_int_pin = 2; break; default: dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n"); - err = -EINVAL; - goto init_error; + return -EINVAL; } + return 0; +} + +int st_sensors_init_sensor(struct iio_dev *indio_dev, + struct st_sensors_platform_data *pdata) +{ + struct st_sensor_data *sdata = iio_priv(indio_dev); + int err = 0; + + mutex_init(&sdata->tb.buf_lock); + + if (pdata) + err = st_sensors_set_drdy_int_pin(indio_dev, pdata); + err = st_sensors_set_enable(indio_dev, false); if (err < 0) - goto init_error; + return err; - err = st_sensors_set_fullscale(indio_dev, - sdata->current_fullscale->num); - if (err < 0) - goto init_error; + if (sdata->current_fullscale) { + err = st_sensors_set_fullscale(indio_dev, + sdata->current_fullscale->num); + if (err < 0) + return err; + } else + dev_info(&indio_dev->dev, "Full-scale not possible\n"); err = st_sensors_set_odr(indio_dev, sdata->odr); if (err < 0) - goto init_error; + return err; /* set BDU */ err = st_sensors_write_data_with_mask(indio_dev, sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true); if (err < 0) - goto init_error; + return err; err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); -init_error: return err; } EXPORT_SYMBOL(st_sensors_init_sensor); @@ -263,6 +273,9 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) u8 drdy_mask; struct st_sensor_data *sdata = iio_priv(indio_dev); + if (!sdata->sensor->drdy_irq.addr) + return 0; + /* Enable/Disable the interrupt generator 1. */ if (sdata->sensor->drdy_irq.ig1.en_addr > 0) { err = st_sensors_write_data_with_mask(indio_dev, @@ -318,10 +331,8 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, unsigned int byte_for_channel = ch->scan_type.storagebits >> 3; outdata = kmalloc(byte_for_channel, GFP_KERNEL); - if (!outdata) { - err = -EINVAL; - goto st_sensors_read_axis_data_error; - } + if (!outdata) + return -ENOMEM; err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, ch->address, byte_for_channel, @@ -336,7 +347,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, st_sensors_free_memory: kfree(outdata); -st_sensors_read_axis_data_error: + return err; } @@ -349,28 +360,25 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { err = -EBUSY; - goto read_error; + goto out; } else { err = st_sensors_set_enable(indio_dev, true); if (err < 0) - goto read_error; + goto out; msleep((sdata->sensor->bootime * 1000) / sdata->odr); err = st_sensors_read_axis_data(indio_dev, ch, val); if (err < 0) - goto read_error; + goto out; *val = *val >> ch->scan_type.shift; err = st_sensors_set_enable(indio_dev, false); } +out: mutex_unlock(&indio_dev->mlock); return err; - -read_error: - mutex_unlock(&indio_dev->mlock); - return err; } EXPORT_SYMBOL(st_sensors_read_info_raw); diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 3c6a78a75b78..f378ca8033db 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -57,7 +57,7 @@ config AD5446 Say yes here to build support for Analog Devices AD5300, AD5301, AD5310, AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453, AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612, - AD5620, AD5621, AD5622, AD5640, AD5660, AD5662 DACs. + AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs. To compile this driver as a module, choose M here: the module will be called ad5446. diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index a3a52be4852c..cb9c6366032c 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -239,10 +239,9 @@ static int ad5064_read_raw(struct iio_dev *indio_dev, if (scale_uv < 0) return scale_uv; - scale_uv = (scale_uv * 100) >> chan->scan_type.realbits; - *val = scale_uv / 100000; - *val2 = (scale_uv % 100000) * 10; - return IIO_VAL_INT_PLUS_MICRO; + *val = scale_uv / 1000; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; default: break; } @@ -285,8 +284,9 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { .name = "powerdown", .read = ad5064_read_dac_powerdown, .write = ad5064_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", false, &ad5064_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5064_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5064_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index d2da71ece740..b968af50db0a 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -379,15 +379,14 @@ static int ad5360_read_raw(struct iio_dev *indio_dev, *val = ret >> chan->scan_type.shift; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - /* vout = 4 * vref * dac_code */ - scale_uv = ad5360_get_channel_vref(st, chan->channel) * 4 * 100; + scale_uv = ad5360_get_channel_vref(st, chan->channel); if (scale_uv < 0) return scale_uv; - scale_uv >>= (chan->scan_type.realbits); - *val = scale_uv / 100000; - *val2 = (scale_uv % 100000) * 10; - return IIO_VAL_INT_PLUS_MICRO; + /* vout = 4 * vref * dac_code */ + *val = scale_uv * 4 / 1000; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_CALIBBIAS: ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET, chan->address); diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 1c44ae3920e2..a59ff0e7b888 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -204,7 +204,6 @@ static int ad5380_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) { struct ad5380_state *st = iio_priv(indio_dev); - unsigned long scale_uv; int ret; switch (info) { @@ -225,10 +224,9 @@ static int ad5380_read_raw(struct iio_dev *indio_dev, val -= (1 << chan->scan_type.realbits) / 2; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = ((2 * st->vref) >> chan->scan_type.realbits) * 100; - *val = scale_uv / 100000; - *val2 = (scale_uv % 100000) * 10; - return IIO_VAL_INT_PLUS_MICRO; + *val = 2 * st->vref; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; default: break; } @@ -247,8 +245,10 @@ static struct iio_chan_spec_ext_info ad5380_ext_info[] = { .name = "powerdown", .read = ad5380_read_dac_powerdown, .write = ad5380_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", true, &ad5380_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad5380_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5380_powerdown_mode_enum), { }, }; @@ -269,72 +269,72 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = { [ID_AD5380_3] = { .channel_template = AD5380_CHANNEL(14), .num_channels = 40, - .int_vref = 1250000, + .int_vref = 1250, }, [ID_AD5380_5] = { .channel_template = AD5380_CHANNEL(14), .num_channels = 40, - .int_vref = 2500000, + .int_vref = 2500, }, [ID_AD5381_3] = { .channel_template = AD5380_CHANNEL(12), .num_channels = 16, - .int_vref = 1250000, + .int_vref = 1250, }, [ID_AD5381_5] = { .channel_template = AD5380_CHANNEL(12), .num_channels = 16, - .int_vref = 2500000, + .int_vref = 2500, }, [ID_AD5382_3] = { .channel_template = AD5380_CHANNEL(14), .num_channels = 32, - .int_vref = 1250000, + .int_vref = 1250, }, [ID_AD5382_5] = { .channel_template = AD5380_CHANNEL(14), .num_channels = 32, - .int_vref = 2500000, + .int_vref = 2500, }, [ID_AD5383_3] = { .channel_template = AD5380_CHANNEL(12), .num_channels = 32, - .int_vref = 1250000, + .int_vref = 1250, }, [ID_AD5383_5] = { .channel_template = AD5380_CHANNEL(12), .num_channels = 32, - .int_vref = 2500000, + .int_vref = 2500, }, [ID_AD5390_3] = { .channel_template = AD5380_CHANNEL(14), .num_channels = 16, - .int_vref = 1250000, + .int_vref = 1250, }, [ID_AD5390_5] = { .channel_template = AD5380_CHANNEL(14), .num_channels = 16, - .int_vref = 2500000, + .int_vref = 2500, }, [ID_AD5391_3] = { .channel_template = AD5380_CHANNEL(12), .num_channels = 16, - .int_vref = 1250000, + .int_vref = 1250, }, [ID_AD5391_5] = { .channel_template = AD5380_CHANNEL(12), .num_channels = 16, - .int_vref = 2500000, + .int_vref = 2500, }, [ID_AD5392_3] = { .channel_template = AD5380_CHANNEL(14), .num_channels = 8, - .int_vref = 1250000, + .int_vref = 1250, }, [ID_AD5392_5] = { .channel_template = AD5380_CHANNEL(14), .num_channels = 8, - .int_vref = 2500000, + .int_vref = 2500, }, }; @@ -393,7 +393,7 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, return ret; } - if (st->chip_info->int_vref == 2500000) + if (st->chip_info->int_vref == 2500) ctrl |= AD5380_CTRL_INT_VREF_2V5; st->vref_reg = devm_regulator_get(dev, "vref"); @@ -409,7 +409,7 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, if (ret < 0) goto error_disable_reg; - st->vref = ret; + st->vref = ret / 1000; } else { st->vref = st->chip_info->int_vref; ctrl |= AD5380_CTRL_INT_VREF_EN; diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 1f78b14abb7d..c44afeb06f56 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -80,6 +80,29 @@ struct ad5421_state { } data[2] ____cacheline_aligned; }; +static const struct iio_event_spec ad5421_current_event[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_event_spec ad5421_temp_event[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + static const struct iio_chan_spec ad5421_channels[] = { { .type = IIO_CURRENT, @@ -92,13 +115,14 @@ static const struct iio_chan_spec ad5421_channels[] = { .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), .scan_type = IIO_ST('u', 16, 16, 0), - .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), + .event_spec = ad5421_current_event, + .num_event_specs = ARRAY_SIZE(ad5421_current_event), }, { .type = IIO_TEMP, .channel = -1, - .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), + .event_spec = ad5421_temp_event, + .num_event_specs = ARRAY_SIZE(ad5421_temp_event), }, }; @@ -281,18 +305,11 @@ static inline unsigned int ad5421_get_offset(struct ad5421_state *st) return (min * (1 << 16)) / (max - min); } -static inline unsigned int ad5421_get_scale(struct ad5421_state *st) -{ - unsigned int min, max; - - ad5421_get_current_min_max(st, &min, &max); - return ((max - min) * 1000) / (1 << 16); -} - static int ad5421_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long m) { struct ad5421_state *st = iio_priv(indio_dev); + unsigned int min, max; int ret; if (chan->type != IIO_CURRENT) @@ -306,9 +323,10 @@ static int ad5421_read_raw(struct iio_dev *indio_dev, *val = ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = ad5421_get_scale(st); - return IIO_VAL_INT_PLUS_MICRO; + ad5421_get_current_min_max(st, &min, &max); + *val = max - min; + *val2 = (1 << 16) * 1000; + return IIO_VAL_FRACTIONAL; case IIO_CHAN_INFO_OFFSET: *val = ad5421_get_offset(st); return IIO_VAL_INT; @@ -359,15 +377,15 @@ static int ad5421_write_raw(struct iio_dev *indio_dev, } static int ad5421_write_event_config(struct iio_dev *indio_dev, - u64 event_code, int state) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) { struct ad5421_state *st = iio_priv(indio_dev); unsigned int mask; - switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + switch (chan->type) { case IIO_CURRENT: - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING) + if (dir == IIO_EV_DIR_RISING) mask = AD5421_FAULT_OVER_CURRENT; else mask = AD5421_FAULT_UNDER_CURRENT; @@ -390,15 +408,15 @@ static int ad5421_write_event_config(struct iio_dev *indio_dev, } static int ad5421_read_event_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) { struct ad5421_state *st = iio_priv(indio_dev); unsigned int mask; - switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + switch (chan->type) { case IIO_CURRENT: - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING) + if (dir == IIO_EV_DIR_RISING) mask = AD5421_FAULT_OVER_CURRENT; else mask = AD5421_FAULT_UNDER_CURRENT; @@ -413,12 +431,14 @@ static int ad5421_read_event_config(struct iio_dev *indio_dev, return (bool)(st->fault_mask & mask); } -static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code, - int *val) +static int ad5421_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, int *val, + int *val2) { int ret; - switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + switch (chan->type) { case IIO_CURRENT: ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA); if (ret < 0) @@ -432,15 +452,15 @@ static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code, return -EINVAL; } - return 0; + return IIO_VAL_INT; } static const struct iio_info ad5421_info = { .read_raw = ad5421_read_raw, .write_raw = ad5421_write_raw, - .read_event_config = ad5421_read_event_config, - .write_event_config = ad5421_write_event_config, - .read_event_value = ad5421_read_event_value, + .read_event_config_new = ad5421_read_event_config, + .write_event_config_new = ad5421_write_event_config, + .read_event_value_new = ad5421_read_event_value, .driver_module = THIS_MODULE, }; diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 96e9ed4c2d01..1263b0e5ad84 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -132,8 +132,9 @@ static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { .name = "powerdown", .read = ad5446_read_dac_powerdown, .write = ad5446_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", false, &ad5446_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum), { }, }; @@ -162,18 +163,15 @@ static int ad5446_read_raw(struct iio_dev *indio_dev, long m) { struct ad5446_state *st = iio_priv(indio_dev); - unsigned long scale_uv; switch (m) { case IIO_CHAN_INFO_RAW: *val = st->cached_val; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; - + *val = st->vref_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } @@ -329,6 +327,7 @@ enum ad5446_supported_spi_device_ids { ID_AD5601, ID_AD5611, ID_AD5621, + ID_AD5641, ID_AD5620_2500, ID_AD5620_1250, ID_AD5640_2500, @@ -391,6 +390,10 @@ static const struct ad5446_chip_info ad5446_spi_chip_info[] = { .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), .write = ad5446_write, }, + [ID_AD5641] = { + .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), + .write = ad5446_write, + }, [ID_AD5620_2500] = { .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), .int_vref_mv = 2500, @@ -445,6 +448,7 @@ static const struct spi_device_id ad5446_spi_ids[] = { {"ad5601", ID_AD5601}, {"ad5611", ID_AD5611}, {"ad5621", ID_AD5621}, + {"ad5641", ID_AD5641}, {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */ {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */ {"ad5640-2500", ID_AD5640_2500}, diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c index fff7d0762c0c..82e208f6cde2 100644 --- a/drivers/iio/dac/ad5449.c +++ b/drivers/iio/dac/ad5449.c @@ -101,7 +101,6 @@ static int ad5449_read(struct iio_dev *indio_dev, unsigned int addr, { struct ad5449 *st = iio_priv(indio_dev); int ret; - struct spi_message msg; struct spi_transfer t[] = { { .tx_buf = &st->data[0], @@ -114,15 +113,11 @@ static int ad5449_read(struct iio_dev *indio_dev, unsigned int addr, }, }; - spi_message_init(&msg); - spi_message_add_tail(&t[0], &msg); - spi_message_add_tail(&t[1], &msg); - mutex_lock(&indio_dev->mlock); st->data[0] = cpu_to_be16(addr << 12); st->data[1] = cpu_to_be16(AD5449_CMD_NOOP); - ret = spi_sync(st->spi, &msg); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret < 0) goto out_unlock; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index caffb16bc05c..c0957a918e17 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -100,7 +100,6 @@ static int ad5504_read_raw(struct iio_dev *indio_dev, long m) { struct ad5504_state *st = iio_priv(indio_dev); - unsigned long scale_uv; int ret; switch (m) { @@ -113,11 +112,9 @@ static int ad5504_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; - + *val = st->vref_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } @@ -248,8 +245,10 @@ static const struct iio_chan_spec_ext_info ad5504_ext_info[] = { .name = "powerdown", .read = ad5504_read_dac_powerdown, .write = ad5504_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", true, &ad5504_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad5504_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5504_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 714af757cd56..774dd968145b 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -50,15 +50,12 @@ static int ad5624r_read_raw(struct iio_dev *indio_dev, long m) { struct ad5624r_state *st = iio_priv(indio_dev); - unsigned long scale_uv; switch (m) { case IIO_CHAN_INFO_SCALE: - scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; - + *val = st->vref_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } @@ -163,8 +160,10 @@ static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = { .name = "powerdown", .read = ad5624r_read_dac_powerdown, .write = ad5624r_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", true, &ad5624r_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad5624r_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5624r_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 57825ead7db2..30e506e37dd2 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -201,7 +201,6 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, long m) { struct ad5686_state *st = iio_priv(indio_dev); - unsigned long scale_uv; int ret; switch (m) { @@ -213,14 +212,10 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, return ret; *val = ret; return IIO_VAL_INT; - break; case IIO_CHAN_INFO_SCALE: - scale_uv = (st->vref_mv * 100000) - >> (chan->scan_type.realbits); - *val = scale_uv / 100000; - *val2 = (scale_uv % 100000) * 10; - return IIO_VAL_INT_PLUS_MICRO; - + *val = st->vref_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } @@ -265,8 +260,9 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { .name = "powerdown", .read = ad5686_read_dac_powerdown, .write = ad5686_write_dac_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", false, &ad5686_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5686_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5686_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 36a4361aece1..bd31dbc340c1 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -253,15 +253,6 @@ static inline int ad5755_get_offset(struct ad5755_state *st, return (min * (1 << chan->scan_type.realbits)) / (max - min); } -static inline int ad5755_get_scale(struct ad5755_state *st, - struct iio_chan_spec const *chan) -{ - int min, max; - - ad5755_get_min_max(st, chan, &min, &max); - return ((max - min) * 1000000000ULL) >> chan->scan_type.realbits; -} - static int ad5755_chan_reg_info(struct ad5755_state *st, struct iio_chan_spec const *chan, long info, bool write, unsigned int *reg, unsigned int *shift, unsigned int *offset) @@ -303,13 +294,15 @@ static int ad5755_read_raw(struct iio_dev *indio_dev, { struct ad5755_state *st = iio_priv(indio_dev); unsigned int reg, shift, offset; + int min, max; int ret; switch (info) { case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = ad5755_get_scale(st, chan); - return IIO_VAL_INT_PLUS_NANO; + ad5755_get_min_max(st, chan, &min, &max); + *val = max - min; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: *val = ad5755_get_offset(st, chan); return IIO_VAL_INT; @@ -386,6 +379,7 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = { .name = "powerdown", .read = ad5755_read_powerdown, .write = ad5755_write_powerdown, + .shared = IIO_SEPARATE, }, { }, }; diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index df7e028d9db5..a8ff5b2ed13e 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -217,7 +217,6 @@ static int ad5764_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) { struct ad5764_state *st = iio_priv(indio_dev); - unsigned long scale_uv; unsigned int reg; int vref; int ret; @@ -245,15 +244,14 @@ static int ad5764_read_raw(struct iio_dev *indio_dev, *val = sign_extend32(*val, 5); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - /* vout = 4 * vref + ((dac_code / 65535) - 0.5) */ + /* vout = 4 * vref + ((dac_code / 65536) - 0.5) */ vref = ad5764_get_channel_vref(st, chan->channel); if (vref < 0) return vref; - scale_uv = (vref * 4 * 100) >> chan->scan_type.realbits; - *val = scale_uv / 100000; - *val2 = (scale_uv % 100000) * 10; - return IIO_VAL_INT_PLUS_MICRO; + *val = vref * 4 / 1000; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: *val = -(1 << chan->scan_type.realbits) / 2; return IIO_VAL_INT; diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index ce7458963309..d64acbd89482 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -270,9 +270,9 @@ static int ad5791_read_raw(struct iio_dev *indio_dev, *val >>= chan->scan_type.shift; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits; - return IIO_VAL_INT_PLUS_MICRO; + *val = st->vref_mv; + *val2 = (1 << chan->scan_type.realbits) - 1; + return IIO_VAL_FRACTIONAL; case IIO_CHAN_INFO_OFFSET: val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits); do_div(val64, st->vref_mv); @@ -287,11 +287,12 @@ static int ad5791_read_raw(struct iio_dev *indio_dev, static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { { .name = "powerdown", - .shared = true, + .shared = IIO_SHARED_BY_TYPE, .read = ad5791_read_dac_powerdown, .write = ad5791_write_dac_powerdown, }, - IIO_ENUM("powerdown_mode", true, &ad5791_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad5791_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &ad5791_powerdown_mode_enum), { }, }; diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index ed2d276477bd..d0505fd22ef4 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -169,6 +169,7 @@ static const struct iio_chan_spec_ext_info ad7303_ext_info[] = { .name = "powerdown", .read = ad7303_read_dac_powerdown, .write = ad7303_write_dac_powerdown, + .shared = IIO_SEPARATE, }, { }, }; diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index 83adcbf1a205..d26be14fff64 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -82,15 +82,13 @@ static int max517_read_raw(struct iio_dev *indio_dev, long m) { struct max517_data *data = iio_priv(indio_dev); - unsigned int scale_uv; switch (m) { case IIO_CHAN_INFO_SCALE: /* Corresponds to Vref / 2^(bits) */ - scale_uv = (data->vref_mv[chan->channel] * 1000) >> 8; - *val = scale_uv / 1000000; - *val2 = scale_uv % 1000000; - return IIO_VAL_INT_PLUS_MICRO; + *val = data->vref_mv[chan->channel]; + *val2 = 8; + return IIO_VAL_FRACTIONAL_LOG2; default: break; } diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 1397b6e0e414..d982752dd9c4 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -195,8 +195,9 @@ static const struct iio_chan_spec_ext_info mcp4725_ext_info[] = { .name = "powerdown", .read = mcp4725_read_powerdown, .write = mcp4725_write_powerdown, + .shared = IIO_SEPARATE, }, - IIO_ENUM("powerdown_mode", false, &mcp4725_powerdown_mode_enum), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &mcp4725_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", &mcp4725_powerdown_mode_enum), { }, }; @@ -238,17 +239,15 @@ static int mcp4725_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct mcp4725_data *data = iio_priv(indio_dev); - unsigned long scale_uv; switch (mask) { case IIO_CHAN_INFO_RAW: *val = data->dac_value; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = (data->vref_mv * 1000) >> 12; - *val = scale_uv / 1000000; - *val2 = scale_uv % 1000000; - return IIO_VAL_INT_PLUS_MICRO; + *val = data->vref_mv; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 52605c0ea3a6..63a25d9e1204 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -351,6 +351,7 @@ static ssize_t adf4350_read(struct iio_dev *indio_dev, .read = adf4350_read, \ .write = adf4350_write, \ .private = _ident, \ + .shared = IIO_SEPARATE, \ } static const struct iio_chan_spec_ext_info adf4350_ext_info[] = { diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c index e9ec022ae225..add509837269 100644 --- a/drivers/iio/gyro/adis16080.c +++ b/drivers/iio/gyro/adis16080.c @@ -51,7 +51,6 @@ static int adis16080_read_sample(struct iio_dev *indio_dev, u16 addr, int *val) { struct adis16080_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -66,11 +65,7 @@ static int adis16080_read_sample(struct iio_dev *indio_dev, st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE); - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - - ret = spi_sync(st->us, &m); + ret = spi_sync_transfer(st->us, t, ARRAY_SIZE(t)); if (ret == 0) *val = sign_extend32(be16_to_cpu(st->buf), 11); diff --git a/drivers/iio/gyro/adis16130.c b/drivers/iio/gyro/adis16130.c index ac66fc184042..445c2aecfadd 100644 --- a/drivers/iio/gyro/adis16130.c +++ b/drivers/iio/gyro/adis16130.c @@ -47,7 +47,6 @@ static int adis16130_spi_read(struct iio_dev *indio_dev, u8 reg_addr, u32 *val) { int ret; struct adis16130_state *st = iio_priv(indio_dev); - struct spi_message msg; struct spi_transfer xfer = { .tx_buf = st->buf, .rx_buf = st->buf, @@ -59,10 +58,7 @@ static int adis16130_spi_read(struct iio_dev *indio_dev, u8 reg_addr, u32 *val) st->buf[0] = ADIS16130_CON_RD | reg_addr; st->buf[1] = st->buf[2] = st->buf[3] = 0; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->us, &msg); - + ret = spi_sync_transfer(st->us, &xfer, 1); if (ret == 0) *val = (st->buf[1] << 16) | (st->buf[2] << 8) | st->buf[3]; mutex_unlock(&st->buf_lock); @@ -103,7 +99,6 @@ static int adis16130_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - break; case IIO_CHAN_INFO_OFFSET: switch (chan->type) { case IIO_ANGL_VEL: @@ -115,7 +110,6 @@ static int adis16130_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - break; } return -EINVAL; diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 06541162fc02..22b6fb80fa1a 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -239,7 +239,6 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - break; case IIO_CHAN_INFO_OFFSET: *val = 250000 / 1453; /* 25 C = 0x00 */ return IIO_VAL_INT; diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c index 6dab2995f0f2..1e546ba7ba45 100644 --- a/drivers/iio/gyro/adxrs450.c +++ b/drivers/iio/gyro/adxrs450.c @@ -90,7 +90,6 @@ static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev, u8 reg_address, u16 *val) { - struct spi_message msg; struct adxrs450_state *st = iio_priv(indio_dev); u32 tx; int ret; @@ -114,10 +113,7 @@ static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev, tx |= ADXRS450_P; st->tx = cpu_to_be32(tx); - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n", reg_address); @@ -169,7 +165,6 @@ static int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev, **/ static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val) { - struct spi_message msg; struct adxrs450_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -188,10 +183,7 @@ static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val) mutex_lock(&st->buf_lock); st->tx = cpu_to_be32(ADXRS450_SENSOR_DATA); - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "Problem while reading sensor data\n"); goto error_ret; @@ -354,7 +346,6 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - break; case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW: ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t); if (ret) diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index c688d974d3e3..ea01c6bcfb56 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -182,10 +182,11 @@ static const struct iio_info gyro_3d_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -200,7 +201,7 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, gyro_state->common_attributes.data_ready); if (gyro_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - (u8 *)gyro_state->gyro_val, + gyro_state->gyro_val, sizeof(gyro_state->gyro_val)); return 0; diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c index 6c43af9bb0a4..e3b3c5084070 100644 --- a/drivers/iio/gyro/itg3200_buffer.c +++ b/drivers/iio/gyro/itg3200_buffer.c @@ -55,11 +55,8 @@ static irqreturn_t itg3200_trigger_handler(int irq, void *p) if (ret < 0) goto error_ret; - if (indio_dev->scan_timestamp) - memcpy(buf + indio_dev->scan_bytes - sizeof(s64), - &pf->timestamp, sizeof(pf->timestamp)); + iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp); - iio_push_to_buffers(indio_dev, (u8 *)buf); iio_trigger_notify_done(indio_dev->trig); error_ret: diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c index 69017c7ec302..d67b17b6a7aa 100644 --- a/drivers/iio/gyro/st_gyro_buffer.c +++ b/drivers/iio/gyro/st_gyro_buffer.c @@ -32,16 +32,7 @@ int st_gyro_trig_set_state(struct iio_trigger *trig, bool state) static int st_gyro_buffer_preenable(struct iio_dev *indio_dev) { - int err; - - err = st_sensors_set_enable(indio_dev, true); - if (err < 0) - goto st_gyro_set_enable_error; - - err = iio_sw_buffer_preenable(indio_dev); - -st_gyro_set_enable_error: - return err; + return st_sensors_set_enable(indio_dev, true); } static int st_gyro_buffer_postenable(struct iio_dev *indio_dev) diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index e13c2b0bf3d1..d53d91adfb55 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -305,8 +305,9 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = { int st_gyro_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) { - int err; struct st_sensor_data *gdata = iio_priv(indio_dev); + int irq = gdata->get_irq_data_ready(indio_dev); + int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &gyro_info; @@ -314,7 +315,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors); if (err < 0) - goto st_gyro_common_probe_error; + return err; gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; gdata->multiread_bit = gdata->sensor->multi_read_bit; @@ -327,13 +328,13 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_gyro_common_probe_error; + return err; - if (gdata->get_irq_data_ready(indio_dev) > 0) { - err = st_gyro_allocate_ring(indio_dev); - if (err < 0) - goto st_gyro_common_probe_error; + err = st_gyro_allocate_ring(indio_dev); + if (err < 0) + return err; + if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_GYRO_TRIGGER_OPS); if (err < 0) @@ -344,15 +345,14 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, if (err) goto st_gyro_device_register_error; - return err; + return 0; st_gyro_device_register_error: - if (gdata->get_irq_data_ready(indio_dev) > 0) + if (irq > 0) st_sensors_deallocate_trigger(indio_dev); st_gyro_probe_trigger_error: - if (gdata->get_irq_data_ready(indio_dev) > 0) - st_gyro_deallocate_ring(indio_dev); -st_gyro_common_probe_error: + st_gyro_deallocate_ring(indio_dev); + return err; } EXPORT_SYMBOL(st_gyro_common_probe); @@ -362,10 +362,10 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) struct st_sensor_data *gdata = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (gdata->get_irq_data_ready(indio_dev) > 0) { + if (gdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); - st_gyro_deallocate_ring(indio_dev); - } + + st_gyro_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_gyro_common_remove); diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 9b32253b824b..f6db6af36ba6 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -30,9 +30,12 @@ int __iio_add_chan_devattr(const char *postfix, const char *buf, size_t len), u64 mask, - bool generic, + enum iio_shared_by shared_by, struct device *dev, struct list_head *attr_list); +void iio_free_chan_devattr_list(struct list_head *attr_list); + +ssize_t iio_format_value(char *buf, unsigned int type, int val, int val2); /* Event interface flags */ #define IIO_BUSY_BIT_POS 1 @@ -50,6 +53,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, #define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer) void iio_disable_all_buffers(struct iio_dev *indio_dev); +void iio_buffer_wakeup_poll(struct iio_dev *indio_dev); #else @@ -57,11 +61,13 @@ void iio_disable_all_buffers(struct iio_dev *indio_dev); #define iio_buffer_read_first_n_outer_addr NULL static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {} +static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {} #endif int iio_device_register_eventset(struct iio_dev *indio_dev); void iio_device_unregister_eventset(struct iio_dev *indio_dev); +void iio_device_wakeup_eventset(struct iio_dev *indio_dev); int iio_event_getfd(struct iio_dev *indio_dev); #endif diff --git a/drivers/iio/imu/adis16400_buffer.c b/drivers/iio/imu/adis16400_buffer.c index 054c01d6e73c..f2cf829e5df1 100644 --- a/drivers/iio/imu/adis16400_buffer.c +++ b/drivers/iio/imu/adis16400_buffer.c @@ -82,13 +82,8 @@ irqreturn_t adis16400_trigger_handler(int irq, void *p) spi_setup(st->adis.spi); } - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) { - void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); - *(s64 *)b = pf->timestamp; - } - - iio_push_to_buffers(indio_dev, adis->buffer); + iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, + pf->timestamp); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 99d8e0b0dd34..cb32b593f1c5 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -102,13 +102,8 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) mutex_unlock(&adis->txrx_lock); } - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) { - void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); - *(s64 *)b = pf->timestamp; - } - - iio_push_to_buffers(indio_dev, adis->buffer); + iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, + pf->timestamp); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 7da0832f187b..429517117eff 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -124,7 +124,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) u8 data[INV_MPU6050_OUTPUT_DATA_SIZE]; u16 fifo_count; s64 timestamp; - u64 *tmp; mutex_lock(&indio_dev->mlock); if (!(st->chip_config.accl_fifo_enable | @@ -170,9 +169,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) if (0 == result) timestamp = 0; - tmp = (u64 *)data; - tmp[DIV_ROUND_UP(bytes_per_datum, 8)] = timestamp; - result = iio_push_to_buffers(indio_dev, data); + result = iio_push_to_buffers_with_timestamp(indio_dev, data, + timestamp); if (result) goto flush_fifo; fifo_count -= bytes_per_datum; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 2db7dcd826b9..7f9152c3c4d3 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -20,6 +20,7 @@ #include <linux/cdev.h> #include <linux/slab.h> #include <linux/poll.h> +#include <linux/sched.h> #include <linux/iio/iio.h> #include "iio_core.h" @@ -31,16 +32,9 @@ static const char * const iio_endian_prefix[] = { [IIO_LE] = "le", }; -static bool iio_buffer_is_active(struct iio_dev *indio_dev, - struct iio_buffer *buf) +static bool iio_buffer_is_active(struct iio_buffer *buf) { - struct list_head *p; - - list_for_each(p, &indio_dev->buffer_list) - if (p == &buf->buffer_list) - return true; - - return false; + return !list_empty(&buf->buffer_list); } /** @@ -55,6 +49,9 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; + if (!indio_dev->info) + return -ENODEV; + if (!rb || !rb->access->read_first_n) return -EINVAL; return rb->access->read_first_n(rb, n, buf); @@ -69,6 +66,9 @@ unsigned int iio_buffer_poll(struct file *filp, struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; + if (!indio_dev->info) + return -ENODEV; + poll_wait(filp, &rb->pollq, wait); if (rb->stufftoread) return POLLIN | POLLRDNORM; @@ -76,10 +76,27 @@ unsigned int iio_buffer_poll(struct file *filp, return 0; } +/** + * iio_buffer_wakeup_poll - Wakes up the buffer waitqueue + * @indio_dev: The IIO device + * + * Wakes up the event waitqueue used for poll(). Should usually + * be called when the device is unregistered. + */ +void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) +{ + if (!indio_dev->buffer) + return; + + wake_up(&indio_dev->buffer->pollq); +} + void iio_buffer_init(struct iio_buffer *buffer) { INIT_LIST_HEAD(&buffer->demux_list); + INIT_LIST_HEAD(&buffer->buffer_list); init_waitqueue_head(&buffer->pollq); + kref_init(&buffer->ref); } EXPORT_SYMBOL(iio_buffer_init); @@ -146,7 +163,7 @@ static ssize_t iio_scan_el_store(struct device *dev, if (ret < 0) return ret; mutex_lock(&indio_dev->mlock); - if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) { + if (iio_buffer_is_active(indio_dev->buffer)) { ret = -EBUSY; goto error_ret; } @@ -192,7 +209,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev, return ret; mutex_lock(&indio_dev->mlock); - if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) { + if (iio_buffer_is_active(indio_dev->buffer)) { ret = -EBUSY; goto error_ret; } @@ -214,7 +231,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, &iio_show_scan_index, NULL, 0, - 0, + IIO_SEPARATE, &indio_dev->dev, &buffer->scan_el_dev_attr_list); if (ret) @@ -249,29 +266,14 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 0, &indio_dev->dev, &buffer->scan_el_dev_attr_list); + if (ret) + goto error_ret; attrcount++; ret = attrcount; error_ret: return ret; } -static void iio_buffer_remove_and_free_scan_dev_attr(struct iio_dev *indio_dev, - struct iio_dev_attr *p) -{ - kfree(p->dev_attr.attr.name); - kfree(p); -} - -static void __iio_buffer_attr_cleanup(struct iio_dev *indio_dev) -{ - struct iio_dev_attr *p, *n; - struct iio_buffer *buffer = indio_dev->buffer; - - list_for_each_entry_safe(p, n, - &buffer->scan_el_dev_attr_list, l) - iio_buffer_remove_and_free_scan_dev_attr(indio_dev, p); -} - static const char * const iio_scan_elements_group_name = "scan_elements"; int iio_buffer_register(struct iio_dev *indio_dev, @@ -348,7 +350,7 @@ int iio_buffer_register(struct iio_dev *indio_dev, error_free_scan_mask: kfree(buffer->scan_mask); error_cleanup_dynamic: - __iio_buffer_attr_cleanup(indio_dev); + iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); return ret; } @@ -358,7 +360,7 @@ void iio_buffer_unregister(struct iio_dev *indio_dev) { kfree(indio_dev->buffer->scan_mask); kfree(indio_dev->buffer->scan_el_group.attrs); - __iio_buffer_attr_cleanup(indio_dev); + iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list); } EXPORT_SYMBOL(iio_buffer_unregister); @@ -396,7 +398,7 @@ ssize_t iio_buffer_write_length(struct device *dev, return len; mutex_lock(&indio_dev->mlock); - if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) { + if (iio_buffer_is_active(indio_dev->buffer)) { ret = -EBUSY; } else { if (buffer->access->set_length) @@ -414,13 +416,11 @@ ssize_t iio_buffer_show_enable(struct device *dev, char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - return sprintf(buf, "%d\n", - iio_buffer_is_active(indio_dev, - indio_dev->buffer)); + return sprintf(buf, "%d\n", iio_buffer_is_active(indio_dev->buffer)); } EXPORT_SYMBOL(iio_buffer_show_enable); -/* note NULL used as error indicator as it doesn't make sense. */ +/* Note NULL used as error indicator as it doesn't make sense. */ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks, unsigned int masklength, const unsigned long *mask) @@ -435,8 +435,8 @@ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks, return NULL; } -static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask, - bool timestamp) +static int iio_compute_scan_bytes(struct iio_dev *indio_dev, + const unsigned long *mask, bool timestamp) { const struct iio_chan_spec *ch; unsigned bytes = 0; @@ -460,6 +460,19 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask, return bytes; } +static void iio_buffer_activate(struct iio_dev *indio_dev, + struct iio_buffer *buffer) +{ + iio_buffer_get(buffer); + list_add(&buffer->buffer_list, &indio_dev->buffer_list); +} + +static void iio_buffer_deactivate(struct iio_buffer *buffer) +{ + list_del_init(&buffer->buffer_list); + iio_buffer_put(buffer); +} + void iio_disable_all_buffers(struct iio_dev *indio_dev) { struct iio_buffer *buffer, *_buffer; @@ -472,7 +485,7 @@ void iio_disable_all_buffers(struct iio_dev *indio_dev) list_for_each_entry_safe(buffer, _buffer, &indio_dev->buffer_list, buffer_list) - list_del_init(&buffer->buffer_list); + iio_buffer_deactivate(buffer); indio_dev->currentmode = INDIO_DIRECT_MODE; if (indio_dev->setup_ops->postdisable) @@ -482,7 +495,21 @@ void iio_disable_all_buffers(struct iio_dev *indio_dev) kfree(indio_dev->active_scan_mask); } -int iio_update_buffers(struct iio_dev *indio_dev, +static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, + struct iio_buffer *buffer) +{ + unsigned int bytes; + + if (!buffer->access->set_bytes_per_datum) + return; + + bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask, + buffer->scan_timestamp); + + buffer->access->set_bytes_per_datum(buffer, bytes); +} + +static int __iio_update_buffers(struct iio_dev *indio_dev, struct iio_buffer *insert_buffer, struct iio_buffer *remove_buffer) { @@ -512,9 +539,9 @@ int iio_update_buffers(struct iio_dev *indio_dev, indio_dev->active_scan_mask = NULL; if (remove_buffer) - list_del(&remove_buffer->buffer_list); + iio_buffer_deactivate(remove_buffer); if (insert_buffer) - list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list); + iio_buffer_activate(indio_dev, insert_buffer); /* If no buffers in list, we are done */ if (list_empty(&indio_dev->buffer_list)) { @@ -524,7 +551,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, return 0; } - /* What scan mask do we actually have ?*/ + /* What scan mask do we actually have? */ compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), sizeof(long), GFP_KERNEL); if (compound_mask == NULL) { @@ -549,7 +576,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, * Roll back. * Note can only occur when adding a buffer. */ - list_del(&insert_buffer->buffer_list); + iio_buffer_deactivate(insert_buffer); if (old_mask) { indio_dev->active_scan_mask = old_mask; success = -EINVAL; @@ -579,7 +606,8 @@ int iio_update_buffers(struct iio_dev *indio_dev, iio_compute_scan_bytes(indio_dev, indio_dev->active_scan_mask, indio_dev->scan_timestamp); - list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) { + iio_buffer_update_bytes_per_datum(indio_dev, buffer); if (buffer->access->request_update) { ret = buffer->access->request_update(buffer); if (ret) { @@ -588,6 +616,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, goto error_run_postdisable; } } + } if (indio_dev->info->update_scan_mode) { ret = indio_dev->info ->update_scan_mode(indio_dev, @@ -597,7 +626,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, goto error_run_postdisable; } } - /* Definitely possible for devices to support both of these.*/ + /* Definitely possible for devices to support both of these. */ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) { if (!indio_dev->trig) { printk(KERN_INFO "Buffer not started: no trigger\n"); @@ -608,7 +637,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, indio_dev->currentmode = INDIO_BUFFER_TRIGGERED; } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) { indio_dev->currentmode = INDIO_BUFFER_HARDWARE; - } else { /* should never be reached */ + } else { /* Should never be reached */ ret = -EINVAL; goto error_run_postdisable; } @@ -640,13 +669,50 @@ error_run_postdisable: error_remove_inserted: if (insert_buffer) - list_del(&insert_buffer->buffer_list); + iio_buffer_deactivate(insert_buffer); indio_dev->active_scan_mask = old_mask; kfree(compound_mask); error_ret: return ret; } + +int iio_update_buffers(struct iio_dev *indio_dev, + struct iio_buffer *insert_buffer, + struct iio_buffer *remove_buffer) +{ + int ret; + + if (insert_buffer == remove_buffer) + return 0; + + mutex_lock(&indio_dev->info_exist_lock); + mutex_lock(&indio_dev->mlock); + + if (insert_buffer && iio_buffer_is_active(insert_buffer)) + insert_buffer = NULL; + + if (remove_buffer && !iio_buffer_is_active(remove_buffer)) + remove_buffer = NULL; + + if (!insert_buffer && !remove_buffer) { + ret = 0; + goto out_unlock; + } + + if (indio_dev->info == NULL) { + ret = -ENODEV; + goto out_unlock; + } + + ret = __iio_update_buffers(indio_dev, insert_buffer, remove_buffer); + +out_unlock: + mutex_unlock(&indio_dev->mlock); + mutex_unlock(&indio_dev->info_exist_lock); + + return ret; +} EXPORT_SYMBOL_GPL(iio_update_buffers); ssize_t iio_buffer_store_enable(struct device *dev, @@ -657,7 +723,6 @@ ssize_t iio_buffer_store_enable(struct device *dev, int ret; bool requested_state; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_buffer *pbuf = indio_dev->buffer; bool inlist; ret = strtobool(buf, &requested_state); @@ -667,16 +732,16 @@ ssize_t iio_buffer_store_enable(struct device *dev, mutex_lock(&indio_dev->mlock); /* Find out if it is in the list */ - inlist = iio_buffer_is_active(indio_dev, pbuf); + inlist = iio_buffer_is_active(indio_dev->buffer); /* Already in desired state */ if (inlist == requested_state) goto done; if (requested_state) - ret = iio_update_buffers(indio_dev, + ret = __iio_update_buffers(indio_dev, indio_dev->buffer, NULL); else - ret = iio_update_buffers(indio_dev, + ret = __iio_update_buffers(indio_dev, NULL, indio_dev->buffer); if (ret < 0) @@ -687,24 +752,6 @@ done: } EXPORT_SYMBOL(iio_buffer_store_enable); -int iio_sw_buffer_preenable(struct iio_dev *indio_dev) -{ - struct iio_buffer *buffer; - unsigned bytes; - dev_dbg(&indio_dev->dev, "%s\n", __func__); - - list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) - if (buffer->access->set_bytes_per_datum) { - bytes = iio_compute_scan_bytes(indio_dev, - buffer->scan_mask, - buffer->scan_timestamp); - - buffer->access->set_bytes_per_datum(buffer, bytes); - } - return 0; -} -EXPORT_SYMBOL(iio_sw_buffer_preenable); - /** * iio_validate_scan_mask_onehot() - Validates that exactly one channel is selected * @indio_dev: the iio device @@ -732,6 +779,7 @@ static bool iio_validate_scan_mask(struct iio_dev *indio_dev, /** * iio_scan_mask_set() - set particular bit in the scan mask + * @indio_dev: the iio device * @buffer: the buffer whose scan mask we are interested in * @bit: the bit to be set. * @@ -752,7 +800,7 @@ int iio_scan_mask_set(struct iio_dev *indio_dev, if (trialmask == NULL) return -ENOMEM; if (!indio_dev->masklength) { - WARN_ON("trying to set scanmask prior to registering buffer\n"); + WARN_ON("Trying to set scanmask prior to registering buffer\n"); goto err_invalid_mask; } bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength); @@ -807,8 +855,8 @@ struct iio_demux_table { struct list_head l; }; -static unsigned char *iio_demux(struct iio_buffer *buffer, - unsigned char *datain) +static const void *iio_demux(struct iio_buffer *buffer, + const void *datain) { struct iio_demux_table *t; @@ -821,9 +869,9 @@ static unsigned char *iio_demux(struct iio_buffer *buffer, return buffer->demux_bounce; } -static int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data) +static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data) { - unsigned char *dataout = iio_demux(buffer, data); + const void *dataout = iio_demux(buffer, data); return buffer->access->store_to(buffer, dataout); } @@ -838,7 +886,7 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer) } -int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data) +int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data) { int ret; struct iio_buffer *buf; @@ -961,3 +1009,45 @@ error_clear_mux_table: return ret; } EXPORT_SYMBOL_GPL(iio_update_demux); + +/** + * iio_buffer_release() - Free a buffer's resources + * @ref: Pointer to the kref embedded in the iio_buffer struct + * + * This function is called when the last reference to the buffer has been + * dropped. It will typically free all resources allocated by the buffer. Do not + * call this function manually, always use iio_buffer_put() when done using a + * buffer. + */ +static void iio_buffer_release(struct kref *ref) +{ + struct iio_buffer *buffer = container_of(ref, struct iio_buffer, ref); + + buffer->access->release(buffer); +} + +/** + * iio_buffer_get() - Grab a reference to the buffer + * @buffer: The buffer to grab a reference for, may be NULL + * + * Returns the pointer to the buffer that was passed into the function. + */ +struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer) +{ + if (buffer) + kref_get(&buffer->ref); + + return buffer; +} +EXPORT_SYMBOL_GPL(iio_buffer_get); + +/** + * iio_buffer_put() - Release the reference to the buffer + * @buffer: The buffer to release the reference for, may be NULL + */ +void iio_buffer_put(struct iio_buffer *buffer) +{ + if (buffer) + kref_put(&buffer->ref, iio_buffer_release); +} +EXPORT_SYMBOL_GPL(iio_buffer_put); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index f95c6979efd8..f7211576abe5 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -28,6 +28,7 @@ #include "iio_core_trigger.h" #include <linux/iio/sysfs.h> #include <linux/iio/events.h> +#include <linux/iio/buffer.h> /* IDA to assign each registered device a unique id */ static DEFINE_IDA(iio_ida); @@ -101,6 +102,7 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_PHASE] = "phase", [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain", [IIO_CHAN_INFO_HYSTERESIS] = "hysteresis", + [IIO_CHAN_INFO_INT_TIME] = "integration_time", }; const struct iio_chan_spec @@ -361,22 +363,20 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, } EXPORT_SYMBOL_GPL(iio_enum_write); -static ssize_t iio_read_channel_info(struct device *dev, - struct device_attribute *attr, - char *buf) +/** + * iio_format_value() - Formats a IIO value into its string representation + * @buf: The buffer to which the formated value gets written + * @type: One of the IIO_VAL_... constants. This decides how the val and val2 + * parameters are formatted. + * @val: First part of the value, exact meaning depends on the type parameter. + * @val2: Second part of the value, exact meaning depends on the type parameter. + */ +ssize_t iio_format_value(char *buf, unsigned int type, int val, int val2) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); unsigned long long tmp; - int val, val2; bool scale_db = false; - int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, - &val, &val2, this_attr->address); - - if (ret < 0) - return ret; - switch (ret) { + switch (type) { case IIO_VAL_INT: return sprintf(buf, "%d\n", val); case IIO_VAL_INT_PLUS_MICRO_DB: @@ -408,6 +408,22 @@ static ssize_t iio_read_channel_info(struct device *dev, } } +static ssize_t iio_read_channel_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int val, val2; + int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, + &val, &val2, this_attr->address); + + if (ret < 0) + return ret; + + return iio_format_value(buf, ret, val, val2); +} + /** * iio_str_to_fixpoint() - Parse a fixed-point number from a string * @str: The string to parse @@ -516,14 +532,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, struct device_attribute *attr, const char *buf, size_t len), - bool generic) + enum iio_shared_by shared_by) { - int ret; - char *name_format, *full_postfix; + int ret = 0; + char *name_format = NULL; + char *full_postfix; sysfs_attr_init(&dev_attr->attr); /* Build up postfix of <extend_name>_<modifier>_postfix */ - if (chan->modified && !generic) { + if (chan->modified && (shared_by == IIO_SEPARATE)) { if (chan->extend_name) full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_modifier_names[chan @@ -544,53 +561,78 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, chan->extend_name, postfix); } - if (full_postfix == NULL) { - ret = -ENOMEM; - goto error_ret; - } + if (full_postfix == NULL) + return -ENOMEM; if (chan->differential) { /* Differential can not have modifier */ - if (generic) + switch (shared_by) { + case IIO_SHARED_BY_ALL: + name_format = kasprintf(GFP_KERNEL, "%s", full_postfix); + break; + case IIO_SHARED_BY_DIR: + name_format = kasprintf(GFP_KERNEL, "%s_%s", + iio_direction[chan->output], + full_postfix); + break; + case IIO_SHARED_BY_TYPE: name_format = kasprintf(GFP_KERNEL, "%s_%s-%s_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], iio_chan_type_name_spec[chan->type], full_postfix); - else if (chan->indexed) + break; + case IIO_SEPARATE: + if (!chan->indexed) { + WARN_ON("Differential channels must be indexed\n"); + ret = -EINVAL; + goto error_free_full_postfix; + } name_format - = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s", + = kasprintf(GFP_KERNEL, + "%s_%s%d-%s%d_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], chan->channel, iio_chan_type_name_spec[chan->type], chan->channel2, full_postfix); - else { - WARN_ON("Differential channels must be indexed\n"); - ret = -EINVAL; - goto error_free_full_postfix; + break; } } else { /* Single ended */ - if (generic) - name_format - = kasprintf(GFP_KERNEL, "%s_%s_%s", - iio_direction[chan->output], - iio_chan_type_name_spec[chan->type], - full_postfix); - else if (chan->indexed) - name_format - = kasprintf(GFP_KERNEL, "%s_%s%d_%s", - iio_direction[chan->output], - iio_chan_type_name_spec[chan->type], - chan->channel, - full_postfix); - else + switch (shared_by) { + case IIO_SHARED_BY_ALL: + name_format = kasprintf(GFP_KERNEL, "%s", full_postfix); + break; + case IIO_SHARED_BY_DIR: + name_format = kasprintf(GFP_KERNEL, "%s_%s", + iio_direction[chan->output], + full_postfix); + break; + case IIO_SHARED_BY_TYPE: name_format = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], full_postfix); + break; + + case IIO_SEPARATE: + if (chan->indexed) + name_format + = kasprintf(GFP_KERNEL, "%s_%s%d_%s", + iio_direction[chan->output], + iio_chan_type_name_spec[chan->type], + chan->channel, + full_postfix); + else + name_format + = kasprintf(GFP_KERNEL, "%s_%s_%s", + iio_direction[chan->output], + iio_chan_type_name_spec[chan->type], + full_postfix); + break; + } } if (name_format == NULL) { ret = -ENOMEM; @@ -614,16 +656,11 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, dev_attr->attr.mode |= S_IWUSR; dev_attr->store = writefunc; } - kfree(name_format); - kfree(full_postfix); - - return 0; - error_free_name_format: kfree(name_format); error_free_full_postfix: kfree(full_postfix); -error_ret: + return ret; } @@ -642,7 +679,7 @@ int __iio_add_chan_devattr(const char *postfix, const char *buf, size_t len), u64 mask, - bool generic, + enum iio_shared_by shared_by, struct device *dev, struct list_head *attr_list) { @@ -656,7 +693,7 @@ int __iio_add_chan_devattr(const char *postfix, } ret = __iio_device_attr_init(&iio_attr->dev_attr, postfix, chan, - readfunc, writefunc, generic); + readfunc, writefunc, shared_by); if (ret) goto error_iio_dev_attr_free; iio_attr->c = chan; @@ -664,7 +701,7 @@ int __iio_add_chan_devattr(const char *postfix, list_for_each_entry(t, attr_list, l) if (strcmp(t->dev_attr.attr.name, iio_attr->dev_attr.attr.name) == 0) { - if (!generic) + if (shared_by == IIO_SEPARATE) dev_err(dev, "tried to double register : %s\n", t->dev_attr.attr.name); ret = -EBUSY; @@ -682,46 +719,68 @@ error_ret: return ret; } -static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan) +static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + enum iio_shared_by shared_by, + const long *infomask) { - int ret, attrcount = 0; - int i; - const struct iio_chan_spec_ext_info *ext_info; + int i, ret, attrcount = 0; - if (chan->channel < 0) - return 0; - for_each_set_bit(i, &chan->info_mask_separate, sizeof(long)*8) { - ret = __iio_add_chan_devattr(iio_chan_info_postfix[i], - chan, - &iio_read_channel_info, - &iio_write_channel_info, - i, - 0, - &indio_dev->dev, - &indio_dev->channel_attr_list); - if (ret < 0) - goto error_ret; - attrcount++; - } - for_each_set_bit(i, &chan->info_mask_shared_by_type, sizeof(long)*8) { + for_each_set_bit(i, infomask, sizeof(infomask)*8) { ret = __iio_add_chan_devattr(iio_chan_info_postfix[i], chan, &iio_read_channel_info, &iio_write_channel_info, i, - 1, + shared_by, &indio_dev->dev, &indio_dev->channel_attr_list); - if (ret == -EBUSY) { - ret = 0; + if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) continue; - } else if (ret < 0) { - goto error_ret; - } + else if (ret < 0) + return ret; attrcount++; } + return attrcount; +} + +static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan) +{ + int ret, attrcount = 0; + const struct iio_chan_spec_ext_info *ext_info; + + if (chan->channel < 0) + return 0; + ret = iio_device_add_info_mask_type(indio_dev, chan, + IIO_SEPARATE, + &chan->info_mask_separate); + if (ret < 0) + return ret; + attrcount += ret; + + ret = iio_device_add_info_mask_type(indio_dev, chan, + IIO_SHARED_BY_TYPE, + &chan->info_mask_shared_by_type); + if (ret < 0) + return ret; + attrcount += ret; + + ret = iio_device_add_info_mask_type(indio_dev, chan, + IIO_SHARED_BY_DIR, + &chan->info_mask_shared_by_dir); + if (ret < 0) + return ret; + attrcount += ret; + + ret = iio_device_add_info_mask_type(indio_dev, chan, + IIO_SHARED_BY_ALL, + &chan->info_mask_shared_by_all); + if (ret < 0) + return ret; + attrcount += ret; + if (chan->ext_info) { unsigned int i = 0; for (ext_info = chan->ext_info; ext_info->name; ext_info++) { @@ -740,22 +799,31 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, continue; if (ret) - goto error_ret; + return ret; attrcount++; } } - ret = attrcount; -error_ret: - return ret; + return attrcount; } -static void iio_device_remove_and_free_read_attr(struct iio_dev *indio_dev, - struct iio_dev_attr *p) +/** + * iio_free_chan_devattr_list() - Free a list of IIO device attributes + * @attr_list: List of IIO device attributes + * + * This function frees the memory allocated for each of the IIO device + * attributes in the list. Note: if you want to reuse the list after calling + * this function you have to reinitialize it using INIT_LIST_HEAD(). + */ +void iio_free_chan_devattr_list(struct list_head *attr_list) { - kfree(p->dev_attr.attr.name); - kfree(p); + struct iio_dev_attr *p, *n; + + list_for_each_entry_safe(p, n, attr_list, l) { + kfree(p->dev_attr.attr.name); + kfree(p); + } } static ssize_t iio_show_dev_name(struct device *dev, @@ -771,7 +839,7 @@ static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); static int iio_device_register_sysfs(struct iio_dev *indio_dev) { int i, ret = 0, attrcount, attrn, attrcount_orig = 0; - struct iio_dev_attr *p, *n; + struct iio_dev_attr *p; struct attribute **attr; /* First count elements in any existing group */ @@ -824,11 +892,7 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) return 0; error_clear_attrs: - list_for_each_entry_safe(p, n, - &indio_dev->channel_attr_list, l) { - list_del(&p->l); - iio_device_remove_and_free_read_attr(indio_dev, p); - } + iio_free_chan_devattr_list(&indio_dev->channel_attr_list); return ret; } @@ -836,12 +900,7 @@ error_clear_attrs: static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) { - struct iio_dev_attr *p, *n; - - list_for_each_entry_safe(p, n, &indio_dev->channel_attr_list, l) { - list_del(&p->l); - iio_device_remove_and_free_read_attr(indio_dev, p); - } + iio_free_chan_devattr_list(&indio_dev->channel_attr_list); kfree(indio_dev->chan_attr_group.attrs); } @@ -853,6 +912,8 @@ static void iio_dev_release(struct device *device) iio_device_unregister_eventset(indio_dev); iio_device_unregister_sysfs(indio_dev); + iio_buffer_put(indio_dev->buffer); + ida_simple_remove(&iio_ida, indio_dev->id); kfree(indio_dev); } @@ -995,6 +1056,9 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) int __user *ip = (int __user *)arg; int fd; + if (!indio_dev->info) + return -ENODEV; + if (cmd == IIO_GET_EVENT_FD_IOCTL) { fd = iio_event_getfd(indio_dev); if (copy_to_user(ip, &fd, sizeof(fd))) @@ -1091,6 +1155,10 @@ void iio_device_unregister(struct iio_dev *indio_dev) iio_disable_all_buffers(indio_dev); indio_dev->info = NULL; + + iio_device_wakeup_eventset(indio_dev); + iio_buffer_wakeup_poll(indio_dev); + mutex_unlock(&indio_dev->info_exist_lock); } EXPORT_SYMBOL(iio_device_unregister); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 6be65ef5faa9..dac15b9f9df8 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -76,6 +76,9 @@ static unsigned int iio_event_poll(struct file *filep, struct iio_event_interface *ev_int = indio_dev->event_interface; unsigned int events = 0; + if (!indio_dev->info) + return -ENODEV; + poll_wait(filep, &ev_int->wait, wait); spin_lock_irq(&ev_int->wait.lock); @@ -96,6 +99,9 @@ static ssize_t iio_event_chrdev_read(struct file *filep, unsigned int copied; int ret; + if (!indio_dev->info) + return -ENODEV; + if (count < sizeof(struct iio_event_data)) return -EINVAL; @@ -107,9 +113,14 @@ static ssize_t iio_event_chrdev_read(struct file *filep, } /* Blocking on device; waiting for something to be there */ ret = wait_event_interruptible_locked_irq(ev_int->wait, - !kfifo_is_empty(&ev_int->det_events)); + !kfifo_is_empty(&ev_int->det_events) || + indio_dev->info == NULL); if (ret) goto error_unlock; + if (indio_dev->info == NULL) { + ret = -ENODEV; + goto error_unlock; + } /* Single access device so no one else can get the data */ } @@ -166,7 +177,7 @@ int iio_event_getfd(struct iio_dev *indio_dev) iio_device_get(indio_dev); fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops, - indio_dev, O_RDONLY); + indio_dev, O_RDONLY | O_CLOEXEC); if (fd < 0) { spin_lock_irq(&ev_int->wait.lock); __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); @@ -190,6 +201,27 @@ static const char * const iio_ev_dir_text[] = { [IIO_EV_DIR_FALLING] = "falling" }; +static const char * const iio_ev_info_text[] = { + [IIO_EV_INFO_ENABLE] = "en", + [IIO_EV_INFO_VALUE] = "value", + [IIO_EV_INFO_HYSTERESIS] = "hysteresis", +}; + +static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr) +{ + return attr->c->event_spec[attr->address & 0xffff].dir; +} + +static enum iio_event_type iio_ev_attr_type(struct iio_dev_attr *attr) +{ + return attr->c->event_spec[attr->address & 0xffff].type; +} + +static enum iio_event_info iio_ev_attr_info(struct iio_dev_attr *attr) +{ + return (attr->address >> 16) & 0xffff; +} + static ssize_t iio_ev_state_store(struct device *dev, struct device_attribute *attr, const char *buf, @@ -204,9 +236,14 @@ static ssize_t iio_ev_state_store(struct device *dev, if (ret < 0) return ret; - ret = indio_dev->info->write_event_config(indio_dev, - this_attr->address, - val); + if (indio_dev->info->write_event_config) + ret = indio_dev->info->write_event_config(indio_dev, + this_attr->address, val); + else + ret = indio_dev->info->write_event_config_new(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), val); + return (ret < 0) ? ret : len; } @@ -216,9 +253,15 @@ static ssize_t iio_ev_state_show(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int val = indio_dev->info->read_event_config(indio_dev, - this_attr->address); + int val; + if (indio_dev->info->read_event_config) + val = indio_dev->info->read_event_config(indio_dev, + this_attr->address); + else + val = indio_dev->info->read_event_config_new(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr)); if (val < 0) return val; else @@ -231,14 +274,24 @@ static ssize_t iio_ev_value_show(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int val, ret; - - ret = indio_dev->info->read_event_value(indio_dev, - this_attr->address, &val); - if (ret < 0) - return ret; + int val, val2; + int ret; - return sprintf(buf, "%d\n", val); + if (indio_dev->info->read_event_value) { + ret = indio_dev->info->read_event_value(indio_dev, + this_attr->address, &val); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", val); + } else { + ret = indio_dev->info->read_event_value_new(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), + &val, &val2); + if (ret < 0) + return ret; + return iio_format_value(buf, ret, val, val2); + } } static ssize_t iio_ev_value_store(struct device *dev, @@ -248,25 +301,120 @@ static ssize_t iio_ev_value_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int val; + int val, val2; int ret; - if (!indio_dev->info->write_event_value) + if (!indio_dev->info->write_event_value && + !indio_dev->info->write_event_value_new) return -EINVAL; - ret = kstrtoint(buf, 10, &val); - if (ret) - return ret; - - ret = indio_dev->info->write_event_value(indio_dev, this_attr->address, - val); + if (indio_dev->info->write_event_value) { + ret = kstrtoint(buf, 10, &val); + if (ret) + return ret; + ret = indio_dev->info->write_event_value(indio_dev, + this_attr->address, val); + } else { + ret = iio_str_to_fixpoint(buf, 100000, &val, &val2); + if (ret) + return ret; + ret = indio_dev->info->write_event_value_new(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), + val, val2); + } if (ret < 0) return ret; return len; } -static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, +static int iio_device_add_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int spec_index, + enum iio_event_type type, enum iio_event_direction dir, + enum iio_shared_by shared_by, const unsigned long *mask) +{ + ssize_t (*show)(struct device *, struct device_attribute *, char *); + ssize_t (*store)(struct device *, struct device_attribute *, + const char *, size_t); + unsigned int attrcount = 0; + unsigned int i; + char *postfix; + int ret; + + for_each_set_bit(i, mask, sizeof(*mask)) { + postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", + iio_ev_type_text[type], iio_ev_dir_text[dir], + iio_ev_info_text[i]); + if (postfix == NULL) + return -ENOMEM; + + if (i == IIO_EV_INFO_ENABLE) { + show = iio_ev_state_show; + store = iio_ev_state_store; + } else { + show = iio_ev_value_show; + store = iio_ev_value_store; + } + + ret = __iio_add_chan_devattr(postfix, chan, show, store, + (i << 16) | spec_index, shared_by, &indio_dev->dev, + &indio_dev->event_interface->dev_attr_list); + kfree(postfix); + + if (ret) + return ret; + + attrcount++; + } + + return attrcount; +} + +static int iio_device_add_event_sysfs_new(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan) +{ + int ret = 0, i, attrcount = 0; + enum iio_event_direction dir; + enum iio_event_type type; + + for (i = 0; i < chan->num_event_specs; i++) { + type = chan->event_spec[i].type; + dir = chan->event_spec[i].dir; + + ret = iio_device_add_event(indio_dev, chan, i, type, dir, + IIO_SEPARATE, &chan->event_spec[i].mask_separate); + if (ret < 0) + goto error_ret; + attrcount += ret; + + ret = iio_device_add_event(indio_dev, chan, i, type, dir, + IIO_SHARED_BY_TYPE, + &chan->event_spec[i].mask_shared_by_type); + if (ret < 0) + goto error_ret; + attrcount += ret; + + ret = iio_device_add_event(indio_dev, chan, i, type, dir, + IIO_SHARED_BY_DIR, + &chan->event_spec[i].mask_shared_by_dir); + if (ret < 0) + goto error_ret; + attrcount += ret; + + ret = iio_device_add_event(indio_dev, chan, i, type, dir, + IIO_SHARED_BY_ALL, + &chan->event_spec[i].mask_shared_by_all); + if (ret < 0) + goto error_ret; + attrcount += ret; + } + ret = attrcount; +error_ret: + return ret; +} + +static int iio_device_add_event_sysfs_old(struct iio_dev *indio_dev, struct iio_chan_spec const *chan) { int ret = 0, i, attrcount = 0; @@ -339,15 +487,14 @@ error_ret: return ret; } -static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev) + +static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan) { - struct iio_dev_attr *p, *n; - list_for_each_entry_safe(p, n, - &indio_dev->event_interface-> - dev_attr_list, l) { - kfree(p->dev_attr.attr.name); - kfree(p); - } + if (chan->event_mask) + return iio_device_add_event_sysfs_old(indio_dev, chan); + else + return iio_device_add_event_sysfs_new(indio_dev, chan); } static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev) @@ -369,9 +516,12 @@ static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev) { int j; - for (j = 0; j < indio_dev->num_channels; j++) + for (j = 0; j < indio_dev->num_channels; j++) { if (indio_dev->channels[j].event_mask != 0) return true; + if (indio_dev->channels[j].num_event_specs != 0) + return true; + } return false; } @@ -441,18 +591,32 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) return 0; error_free_setup_event_lines: - __iio_remove_event_config_attrs(indio_dev); + iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list); kfree(indio_dev->event_interface); error_ret: return ret; } +/** + * iio_device_wakeup_eventset - Wakes up the event waitqueue + * @indio_dev: The IIO device + * + * Wakes up the event waitqueue used for poll() and blocking read(). + * Should usually be called when the device is unregistered. + */ +void iio_device_wakeup_eventset(struct iio_dev *indio_dev) +{ + if (indio_dev->event_interface == NULL) + return; + wake_up(&indio_dev->event_interface->wait); +} + void iio_device_unregister_eventset(struct iio_dev *indio_dev) { if (indio_dev->event_interface == NULL) return; - __iio_remove_event_config_attrs(indio_dev); + iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list); kfree(indio_dev->event_interface->group.attrs); kfree(indio_dev->event_interface); } diff --git a/drivers/iio/industrialio-triggered-buffer.c b/drivers/iio/industrialio-triggered-buffer.c index 46c619b0d8c5..d6f54930b34a 100644 --- a/drivers/iio/industrialio-triggered-buffer.c +++ b/drivers/iio/industrialio-triggered-buffer.c @@ -17,7 +17,6 @@ #include <linux/iio/trigger_consumer.h> static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { - .preenable = &iio_sw_buffer_preenable, .postenable = &iio_triggered_buffer_postenable, .predisable = &iio_triggered_buffer_predisable, }; @@ -47,14 +46,17 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev, irqreturn_t (*pollfunc_th)(int irq, void *p), const struct iio_buffer_setup_ops *setup_ops) { + struct iio_buffer *buffer; int ret; - indio_dev->buffer = iio_kfifo_allocate(indio_dev); - if (!indio_dev->buffer) { + buffer = iio_kfifo_allocate(indio_dev); + if (!buffer) { ret = -ENOMEM; goto error_ret; } + iio_device_attach_buffer(indio_dev, buffer); + indio_dev->pollfunc = iio_alloc_pollfunc(pollfunc_bh, pollfunc_th, IRQF_ONESHOT, diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c index a923c78d5cb4..95c6fc81c2c7 100644 --- a/drivers/iio/kfifo_buf.c +++ b/drivers/iio/kfifo_buf.c @@ -7,10 +7,12 @@ #include <linux/mutex.h> #include <linux/iio/kfifo_buf.h> #include <linux/sched.h> +#include <linux/poll.h> struct iio_kfifo { struct iio_buffer buffer; struct kfifo kf; + struct mutex user_lock; int update_needed; }; @@ -31,13 +33,18 @@ static int iio_request_update_kfifo(struct iio_buffer *r) int ret = 0; struct iio_kfifo *buf = iio_to_kfifo(r); - if (!buf->update_needed) - goto error_ret; - kfifo_free(&buf->kf); - ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum, + mutex_lock(&buf->user_lock); + if (buf->update_needed) { + kfifo_free(&buf->kf); + ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum, buf->buffer.length); + buf->update_needed = false; + } else { + kfifo_reset_out(&buf->kf); + } r->stufftoread = false; -error_ret: + mutex_unlock(&buf->user_lock); + return ret; } @@ -94,7 +101,7 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length) } static int iio_store_to_kfifo(struct iio_buffer *r, - u8 *data) + const void *data) { int ret; struct iio_kfifo *kf = iio_to_kfifo(r); @@ -102,7 +109,7 @@ static int iio_store_to_kfifo(struct iio_buffer *r, if (ret != 1) return -EBUSY; r->stufftoread = true; - wake_up_interruptible(&r->pollq); + wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM); return 0; } @@ -113,12 +120,13 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, int ret, copied; struct iio_kfifo *kf = iio_to_kfifo(r); - if (n < r->bytes_per_datum || r->bytes_per_datum == 0) - return -EINVAL; + if (mutex_lock_interruptible(&kf->user_lock)) + return -ERESTARTSYS; - ret = kfifo_to_user(&kf->kf, buf, n, &copied); - if (ret < 0) - return ret; + if (!kfifo_initialized(&kf->kf) || n < kfifo_esize(&kf->kf)) + ret = -EINVAL; + else + ret = kfifo_to_user(&kf->kf, buf, n, &copied); if (kfifo_is_empty(&kf->kf)) r->stufftoread = false; @@ -126,9 +134,22 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, if (!kfifo_is_empty(&kf->kf)) r->stufftoread = true; + mutex_unlock(&kf->user_lock); + if (ret < 0) + return ret; + return copied; } +static void iio_kfifo_buffer_release(struct iio_buffer *buffer) +{ + struct iio_kfifo *kf = iio_to_kfifo(buffer); + + mutex_destroy(&kf->user_lock); + kfifo_free(&kf->kf); + kfree(kf); +} + static const struct iio_buffer_access_funcs kfifo_access_funcs = { .store_to = &iio_store_to_kfifo, .read_first_n = &iio_read_first_n_kfifo, @@ -137,6 +158,7 @@ static const struct iio_buffer_access_funcs kfifo_access_funcs = { .set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo, .get_length = &iio_get_length_kfifo, .set_length = &iio_set_length_kfifo, + .release = &iio_kfifo_buffer_release, }; struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev) @@ -151,13 +173,14 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev) kf->buffer.attrs = &iio_kfifo_attribute_group; kf->buffer.access = &kfifo_access_funcs; kf->buffer.length = 2; + mutex_init(&kf->user_lock); return &kf->buffer; } EXPORT_SYMBOL(iio_kfifo_allocate); void iio_kfifo_free(struct iio_buffer *r) { - kfree(iio_to_kfifo(r)); + iio_buffer_put(r); } EXPORT_SYMBOL(iio_kfifo_free); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index bf9fa0d7aff9..f98c2b509254 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -27,6 +27,29 @@ config APDS9300 To compile this driver as a module, choose M here: the module will be called apds9300. +config CM36651 + depends on I2C + tristate "CM36651 driver" + help + Say Y here if you use cm36651. + This option enables proximity & RGB sensor using + Capella cm36651 device driver. + + To compile this driver as a module, choose M here: + the module will be called cm36651. + +config GP2AP020A00F + tristate "Sharp GP2AP020A00F Proximity/ALS sensor" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here if you have a Sharp GP2AP020A00F proximity/ALS combo-chip + hooked to an I2C bus. + + To compile this driver as a module, choose M here: the + module will be called gp2ap020a00f. + config HID_SENSOR_ALS depends on HID_SENSOR_HUB select IIO_BUFFER @@ -55,6 +78,16 @@ config SENSORS_LM3533 changes. The ALS-control output values can be set per zone for the three current output channels. +config TCS3472 + tristate "TAOS TCS3472 color light-to-digital converter" + depends on I2C + help + If you say yes here you get support for the TAOS TCS3472 + family of color light-to-digital converters with IR filter. + + This driver can also be built as a module. If so, the module + will be called tcs3472. + config SENSORS_TSL2563 tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" depends on I2C @@ -65,6 +98,16 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. +config TSL4531 + tristate "TAOS TSL4531 ambient light sensors" + depends on I2C + help + Say Y here if you want to build a driver for the TAOS TSL4531 family + of ambient light sensors with direct lux output. + + To compile this driver as a module, choose M here: the + module will be called tsl4531. + config VCNL4000 tristate "VCNL4000 combined ALS and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 354ee9ab2379..daa327f39e04 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -5,7 +5,11 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ADJD_S311) += adjd_s311.o obj-$(CONFIG_APDS9300) += apds9300.o +obj-$(CONFIG_CM36651) += cm36651.o +obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o +obj-$(CONFIG_TCS3472) += tcs3472.o +obj-$(CONFIG_TSL4531) += tsl4531.o obj-$(CONFIG_VCNL4000) += vcnl4000.o diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 23cff798598a..83d15c5baf64 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -114,43 +114,6 @@ static int adjd_s311_read_data(struct iio_dev *indio_dev, u8 reg, int *val) return 0; } -static ssize_t adjd_s311_read_int_time(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, char *buf) -{ - struct adjd_s311_data *data = iio_priv(indio_dev); - s32 ret; - - ret = i2c_smbus_read_word_data(data->client, - ADJD_S311_INT_REG(chan->address)); - if (ret < 0) - return ret; - - return sprintf(buf, "%d\n", ret & ADJD_S311_INT_MASK); -} - -static ssize_t adjd_s311_write_int_time(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, const char *buf, - size_t len) -{ - struct adjd_s311_data *data = iio_priv(indio_dev); - unsigned long int_time; - int ret; - - ret = kstrtoul(buf, 10, &int_time); - if (ret) - return ret; - - if (int_time > ADJD_S311_INT_MASK) - return -EINVAL; - - ret = i2c_smbus_write_word_data(data->client, - ADJD_S311_INT_REG(chan->address), int_time); - if (ret < 0) - return ret; - - return len; -} - static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -175,10 +138,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) len += 2; } - if (indio_dev->scan_timestamp) - *(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64))) - = time_ns; - iio_push_to_buffers(indio_dev, (u8 *)data->buffer); + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, time_ns); done: iio_trigger_notify_done(indio_dev->trig); @@ -186,25 +146,16 @@ done: return IRQ_HANDLED; } -static const struct iio_chan_spec_ext_info adjd_s311_ext_info[] = { - { - .name = "integration_time", - .read = adjd_s311_read_int_time, - .write = adjd_s311_write_int_time, - }, - { } -}; - #define ADJD_S311_CHANNEL(_color, _scan_idx) { \ .type = IIO_INTENSITY, \ .modified = 1, \ .address = (IDX_##_color), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ + BIT(IIO_CHAN_INFO_INT_TIME), \ .channel2 = (IIO_MOD_LIGHT_##_color), \ .scan_index = (_scan_idx), \ .scan_type = IIO_ST('u', 10, 16, 0), \ - .ext_info = adjd_s311_ext_info, \ } static const struct iio_chan_spec adjd_s311_channels[] = { @@ -236,6 +187,18 @@ static int adjd_s311_read_raw(struct iio_dev *indio_dev, return ret; *val = ret & ADJD_S311_CAP_MASK; return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + ret = i2c_smbus_read_word_data(data->client, + ADJD_S311_INT_REG(chan->address)); + if (ret < 0) + return ret; + *val = 0; + /* + * not documented, based on measurement: + * 4095 LSBs correspond to roughly 4 ms + */ + *val2 = ret & ADJD_S311_INT_MASK; + return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; } @@ -245,16 +208,20 @@ static int adjd_s311_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct adjd_s311_data *data = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_HARDWAREGAIN: if (val < 0 || val > ADJD_S311_CAP_MASK) return -EINVAL; - ret = i2c_smbus_write_byte_data(data->client, + return i2c_smbus_write_byte_data(data->client, ADJD_S311_CAP_REG(chan->address), val); - return ret; + case IIO_CHAN_INFO_INT_TIME: + if (val != 0 || val2 < 0 || val2 > ADJD_S311_INT_MASK) + return -EINVAL; + + return i2c_smbus_write_word_data(data->client, + ADJD_S311_INT_REG(chan->address), val2); } return -EINVAL; } diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 66a58bda6dc8..51097bbd59c9 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -273,12 +273,14 @@ static int apds9300_read_raw(struct iio_dev *indio_dev, return ret; } -static int apds9300_read_thresh(struct iio_dev *indio_dev, u64 event_code, - int *val) +static int apds9300_read_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int *val, int *val2) { struct apds9300_data *data = iio_priv(indio_dev); - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + switch (dir) { case IIO_EV_DIR_RISING: *val = data->thresh_hi; break; @@ -289,17 +291,19 @@ static int apds9300_read_thresh(struct iio_dev *indio_dev, u64 event_code, return -EINVAL; } - return 0; + return IIO_VAL_INT; } -static int apds9300_write_thresh(struct iio_dev *indio_dev, u64 event_code, - int val) +static int apds9300_write_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, int val, + int val2) { struct apds9300_data *data = iio_priv(indio_dev); int ret; mutex_lock(&data->mutex); - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING) + if (dir == IIO_EV_DIR_RISING) ret = apds9300_set_thresh_hi(data, val); else ret = apds9300_set_thresh_low(data, val); @@ -309,7 +313,9 @@ static int apds9300_write_thresh(struct iio_dev *indio_dev, u64 event_code, } static int apds9300_read_interrupt_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { struct apds9300_data *data = iio_priv(indio_dev); @@ -317,7 +323,8 @@ static int apds9300_read_interrupt_config(struct iio_dev *indio_dev, } static int apds9300_write_interrupt_config(struct iio_dev *indio_dev, - u64 event_code, int state) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) { struct apds9300_data *data = iio_priv(indio_dev); int ret; @@ -337,10 +344,24 @@ static const struct iio_info apds9300_info_no_irq = { static const struct iio_info apds9300_info = { .driver_module = THIS_MODULE, .read_raw = apds9300_read_raw, - .read_event_value = apds9300_read_thresh, - .write_event_value = apds9300_write_thresh, - .read_event_config = apds9300_read_interrupt_config, - .write_event_config = apds9300_write_interrupt_config, + .read_event_value_new = apds9300_read_thresh, + .write_event_value_new = apds9300_write_thresh, + .read_event_config_new = apds9300_read_interrupt_config, + .write_event_config_new = apds9300_write_interrupt_config, +}; + +static const struct iio_event_spec apds9300_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, }; static const struct iio_chan_spec apds9300_channels[] = { @@ -355,10 +376,8 @@ static const struct iio_chan_spec apds9300_channels[] = { .channel2 = IIO_MOD_LIGHT_BOTH, .indexed = true, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING)), + .event_spec = apds9300_event_spec, + .num_event_specs = ARRAY_SIZE(apds9300_event_spec), }, { .type = IIO_INTENSITY, .channel = 1, diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c new file mode 100644 index 000000000000..21df57130018 --- /dev/null +++ b/drivers/iio/light/cm36651.c @@ -0,0 +1,708 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Author: Beomho Seo <beomho.seo@samsung.com> + * + * 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/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/regulator/consumer.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/events.h> + +/* Slave address 0x19 for PS of 7 bit addressing protocol for I2C */ +#define CM36651_I2C_ADDR_PS 0x19 +/* Alert Response Address */ +#define CM36651_ARA 0x0C + +/* Ambient light sensor */ +#define CM36651_CS_CONF1 0x00 +#define CM36651_CS_CONF2 0x01 +#define CM36651_ALS_WH_M 0x02 +#define CM36651_ALS_WH_L 0x03 +#define CM36651_ALS_WL_M 0x04 +#define CM36651_ALS_WL_L 0x05 +#define CM36651_CS_CONF3 0x06 +#define CM36651_CS_CONF_REG_NUM 0x02 + +/* Proximity sensor */ +#define CM36651_PS_CONF1 0x00 +#define CM36651_PS_THD 0x01 +#define CM36651_PS_CANC 0x02 +#define CM36651_PS_CONF2 0x03 +#define CM36651_PS_REG_NUM 0x04 + +/* CS_CONF1 command code */ +#define CM36651_ALS_ENABLE 0x00 +#define CM36651_ALS_DISABLE 0x01 +#define CM36651_ALS_INT_EN 0x02 +#define CM36651_ALS_THRES 0x04 + +/* CS_CONF2 command code */ +#define CM36651_CS_CONF2_DEFAULT_BIT 0x08 + +/* CS_CONF3 channel integration time */ +#define CM36651_CS_IT1 0x00 /* Integration time 80000 usec */ +#define CM36651_CS_IT2 0x40 /* Integration time 160000 usec */ +#define CM36651_CS_IT3 0x80 /* Integration time 320000 usec */ +#define CM36651_CS_IT4 0xC0 /* Integration time 640000 usec */ + +/* PS_CONF1 command code */ +#define CM36651_PS_ENABLE 0x00 +#define CM36651_PS_DISABLE 0x01 +#define CM36651_PS_INT_EN 0x02 +#define CM36651_PS_PERS2 0x04 +#define CM36651_PS_PERS3 0x08 +#define CM36651_PS_PERS4 0x0C + +/* PS_CONF1 command code: integration time */ +#define CM36651_PS_IT1 0x00 /* Integration time 320 usec */ +#define CM36651_PS_IT2 0x10 /* Integration time 420 usec */ +#define CM36651_PS_IT3 0x20 /* Integration time 520 usec */ +#define CM36651_PS_IT4 0x30 /* Integration time 640 usec */ + +/* PS_CONF1 command code: duty ratio */ +#define CM36651_PS_DR1 0x00 /* Duty ratio 1/80 */ +#define CM36651_PS_DR2 0x40 /* Duty ratio 1/160 */ +#define CM36651_PS_DR3 0x80 /* Duty ratio 1/320 */ +#define CM36651_PS_DR4 0xC0 /* Duty ratio 1/640 */ + +/* PS_THD command code */ +#define CM36651_PS_INITIAL_THD 0x05 + +/* PS_CANC command code */ +#define CM36651_PS_CANC_DEFAULT 0x00 + +/* PS_CONF2 command code */ +#define CM36651_PS_HYS1 0x00 +#define CM36651_PS_HYS2 0x01 +#define CM36651_PS_SMART_PERS_EN 0x02 +#define CM36651_PS_DIR_INT 0x04 +#define CM36651_PS_MS 0x10 + +#define CM36651_CS_COLOR_NUM 4 + +#define CM36651_CLOSE_PROXIMITY 0x32 +#define CM36651_FAR_PROXIMITY 0x33 + +#define CM36651_CS_INT_TIME_AVAIL "80000 160000 320000 640000" +#define CM36651_PS_INT_TIME_AVAIL "320 420 520 640" + +enum cm36651_operation_mode { + CM36651_LIGHT_EN, + CM36651_PROXIMITY_EN, + CM36651_PROXIMITY_EV_EN, +}; + +enum cm36651_light_channel_idx { + CM36651_LIGHT_CHANNEL_IDX_RED, + CM36651_LIGHT_CHANNEL_IDX_GREEN, + CM36651_LIGHT_CHANNEL_IDX_BLUE, + CM36651_LIGHT_CHANNEL_IDX_CLEAR, +}; + +enum cm36651_command { + CM36651_CMD_READ_RAW_LIGHT, + CM36651_CMD_READ_RAW_PROXIMITY, + CM36651_CMD_PROX_EV_EN, + CM36651_CMD_PROX_EV_DIS, +}; + +static const u8 cm36651_cs_reg[CM36651_CS_CONF_REG_NUM] = { + CM36651_CS_CONF1, + CM36651_CS_CONF2, +}; + +static const u8 cm36651_ps_reg[CM36651_PS_REG_NUM] = { + CM36651_PS_CONF1, + CM36651_PS_THD, + CM36651_PS_CANC, + CM36651_PS_CONF2, +}; + +struct cm36651_data { + const struct cm36651_platform_data *pdata; + struct i2c_client *client; + struct i2c_client *ps_client; + struct i2c_client *ara_client; + struct mutex lock; + struct regulator *vled_reg; + unsigned long flags; + int cs_int_time[CM36651_CS_COLOR_NUM]; + int ps_int_time; + u8 cs_ctrl_regs[CM36651_CS_CONF_REG_NUM]; + u8 ps_ctrl_regs[CM36651_PS_REG_NUM]; + u16 color[CM36651_CS_COLOR_NUM]; +}; + +static int cm36651_setup_reg(struct cm36651_data *cm36651) +{ + struct i2c_client *client = cm36651->client; + struct i2c_client *ps_client = cm36651->ps_client; + int i, ret; + + /* CS initialization */ + cm36651->cs_ctrl_regs[CM36651_CS_CONF1] = CM36651_ALS_ENABLE | + CM36651_ALS_THRES; + cm36651->cs_ctrl_regs[CM36651_CS_CONF2] = CM36651_CS_CONF2_DEFAULT_BIT; + + for (i = 0; i < CM36651_CS_CONF_REG_NUM; i++) { + ret = i2c_smbus_write_byte_data(client, cm36651_cs_reg[i], + cm36651->cs_ctrl_regs[i]); + if (ret < 0) + return ret; + } + + /* PS initialization */ + cm36651->ps_ctrl_regs[CM36651_PS_CONF1] = CM36651_PS_ENABLE | + CM36651_PS_IT2; + cm36651->ps_ctrl_regs[CM36651_PS_THD] = CM36651_PS_INITIAL_THD; + cm36651->ps_ctrl_regs[CM36651_PS_CANC] = CM36651_PS_CANC_DEFAULT; + cm36651->ps_ctrl_regs[CM36651_PS_CONF2] = CM36651_PS_HYS2 | + CM36651_PS_DIR_INT | CM36651_PS_SMART_PERS_EN; + + for (i = 0; i < CM36651_PS_REG_NUM; i++) { + ret = i2c_smbus_write_byte_data(ps_client, cm36651_ps_reg[i], + cm36651->ps_ctrl_regs[i]); + if (ret < 0) + return ret; + } + + /* Set shutdown mode */ + ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1, + CM36651_ALS_DISABLE); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(cm36651->ps_client, + CM36651_PS_CONF1, CM36651_PS_DISABLE); + if (ret < 0) + return ret; + + return 0; +} + +static int cm36651_read_output(struct cm36651_data *cm36651, + struct iio_chan_spec const *chan, int *val) +{ + struct i2c_client *client = cm36651->client; + int ret = -EINVAL; + + switch (chan->type) { + case IIO_LIGHT: + *val = i2c_smbus_read_word_data(client, chan->address); + if (*val < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1, + CM36651_ALS_DISABLE); + if (ret < 0) + return ret; + + ret = IIO_VAL_INT; + break; + case IIO_PROXIMITY: + *val = i2c_smbus_read_byte(cm36651->ps_client); + if (*val < 0) + return ret; + + if (!test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) { + ret = i2c_smbus_write_byte_data(cm36651->ps_client, + CM36651_PS_CONF1, CM36651_PS_DISABLE); + if (ret < 0) + return ret; + } + + ret = IIO_VAL_INT; + break; + default: + break; + } + + return ret; +} + +static irqreturn_t cm36651_irq_handler(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct cm36651_data *cm36651 = iio_priv(indio_dev); + struct i2c_client *client = cm36651->client; + int ev_dir, ret; + u64 ev_code; + + /* + * The PS INT pin is an active low signal that PS INT move logic low + * when the object is detect. Once the MCU host received the PS INT + * "LOW" signal, the Host needs to read the data at Alert Response + * Address(ARA) to clear the PS INT signal. After clearing the PS + * INT pin, the PS INT signal toggles from low to high. + */ + ret = i2c_smbus_read_byte(cm36651->ara_client); + if (ret < 0) { + dev_err(&client->dev, + "%s: Data read failed: %d\n", __func__, ret); + return IRQ_HANDLED; + } + switch (ret) { + case CM36651_CLOSE_PROXIMITY: + ev_dir = IIO_EV_DIR_RISING; + break; + case CM36651_FAR_PROXIMITY: + ev_dir = IIO_EV_DIR_FALLING; + break; + default: + dev_err(&client->dev, + "%s: Data read wrong: %d\n", __func__, ret); + return IRQ_HANDLED; + } + + ev_code = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, + CM36651_CMD_READ_RAW_PROXIMITY, + IIO_EV_TYPE_THRESH, ev_dir); + + iio_push_event(indio_dev, ev_code, iio_get_time_ns()); + + return IRQ_HANDLED; +} + +static int cm36651_set_operation_mode(struct cm36651_data *cm36651, int cmd) +{ + struct i2c_client *client = cm36651->client; + struct i2c_client *ps_client = cm36651->ps_client; + int ret = -EINVAL; + + switch (cmd) { + case CM36651_CMD_READ_RAW_LIGHT: + ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1, + cm36651->cs_ctrl_regs[CM36651_CS_CONF1]); + break; + case CM36651_CMD_READ_RAW_PROXIMITY: + if (test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) + return CM36651_PROXIMITY_EV_EN; + + ret = i2c_smbus_write_byte_data(ps_client, CM36651_PS_CONF1, + cm36651->ps_ctrl_regs[CM36651_PS_CONF1]); + break; + case CM36651_CMD_PROX_EV_EN: + if (test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) { + dev_err(&client->dev, + "Already proximity event enable state\n"); + return ret; + } + set_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags); + + ret = i2c_smbus_write_byte_data(ps_client, + cm36651_ps_reg[CM36651_PS_CONF1], + CM36651_PS_INT_EN | CM36651_PS_PERS2 | CM36651_PS_IT2); + + if (ret < 0) { + dev_err(&client->dev, "Proximity enable event failed\n"); + return ret; + } + break; + case CM36651_CMD_PROX_EV_DIS: + if (!test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) { + dev_err(&client->dev, + "Already proximity event disable state\n"); + return ret; + } + clear_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags); + ret = i2c_smbus_write_byte_data(ps_client, + CM36651_PS_CONF1, CM36651_PS_DISABLE); + break; + } + + if (ret < 0) + dev_err(&client->dev, "Write register failed\n"); + + return ret; +} + +static int cm36651_read_channel(struct cm36651_data *cm36651, + struct iio_chan_spec const *chan, int *val) +{ + struct i2c_client *client = cm36651->client; + int cmd, ret; + + if (chan->type == IIO_LIGHT) + cmd = CM36651_CMD_READ_RAW_LIGHT; + else if (chan->type == IIO_PROXIMITY) + cmd = CM36651_CMD_READ_RAW_PROXIMITY; + else + return -EINVAL; + + ret = cm36651_set_operation_mode(cm36651, cmd); + if (ret < 0) { + dev_err(&client->dev, "CM36651 set operation mode failed\n"); + return ret; + } + /* Delay for work after enable operation */ + msleep(50); + ret = cm36651_read_output(cm36651, chan, val); + if (ret < 0) { + dev_err(&client->dev, "CM36651 read output failed\n"); + return ret; + } + + return ret; +} + +static int cm36651_read_int_time(struct cm36651_data *cm36651, + struct iio_chan_spec const *chan, int *val) +{ + switch (chan->type) { + case IIO_LIGHT: + if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1) + *val = 80000; + else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2) + *val = 160000; + else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3) + *val = 320000; + else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4) + *val = 640000; + else + return -EINVAL; + break; + case IIO_PROXIMITY: + if (cm36651->ps_int_time == CM36651_PS_IT1) + *val = 320; + else if (cm36651->ps_int_time == CM36651_PS_IT2) + *val = 420; + else if (cm36651->ps_int_time == CM36651_PS_IT3) + *val = 520; + else if (cm36651->ps_int_time == CM36651_PS_IT4) + *val = 640; + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int cm36651_write_int_time(struct cm36651_data *cm36651, + struct iio_chan_spec const *chan, int val) +{ + struct i2c_client *client = cm36651->client; + struct i2c_client *ps_client = cm36651->ps_client; + int int_time, ret; + + switch (chan->type) { + case IIO_LIGHT: + if (val == 80000) + int_time = CM36651_CS_IT1; + else if (val == 160000) + int_time = CM36651_CS_IT2; + else if (val == 320000) + int_time = CM36651_CS_IT3; + else if (val == 640000) + int_time = CM36651_CS_IT4; + else + return -EINVAL; + + ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF3, + int_time >> 2 * (chan->address)); + if (ret < 0) { + dev_err(&client->dev, "CS integration time write failed\n"); + return ret; + } + cm36651->cs_int_time[chan->address] = int_time; + break; + case IIO_PROXIMITY: + if (val == 320) + int_time = CM36651_PS_IT1; + else if (val == 420) + int_time = CM36651_PS_IT2; + else if (val == 520) + int_time = CM36651_PS_IT3; + else if (val == 640) + int_time = CM36651_PS_IT4; + else + return -EINVAL; + + ret = i2c_smbus_write_byte_data(ps_client, + CM36651_PS_CONF1, int_time); + if (ret < 0) { + dev_err(&client->dev, "PS integration time write failed\n"); + return ret; + } + cm36651->ps_int_time = int_time; + break; + default: + return -EINVAL; + } + + return ret; +} + +static int cm36651_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct cm36651_data *cm36651 = iio_priv(indio_dev); + int ret; + + mutex_lock(&cm36651->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = cm36651_read_channel(cm36651, chan, val); + break; + case IIO_CHAN_INFO_INT_TIME: + ret = cm36651_read_int_time(cm36651, chan, val); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&cm36651->lock); + + return ret; +} + +static int cm36651_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct cm36651_data *cm36651 = iio_priv(indio_dev); + struct i2c_client *client = cm36651->client; + int ret = -EINVAL; + + if (mask == IIO_CHAN_INFO_INT_TIME) { + ret = cm36651_write_int_time(cm36651, chan, val); + if (ret < 0) + dev_err(&client->dev, "Integration time write failed\n"); + } + + return ret; +} + +static int cm36651_read_prox_thresh(struct iio_dev *indio_dev, + u64 event_code, int *val) +{ + struct cm36651_data *cm36651 = iio_priv(indio_dev); + + *val = cm36651->ps_ctrl_regs[CM36651_PS_THD]; + + return 0; +} + +static int cm36651_write_prox_thresh(struct iio_dev *indio_dev, + u64 event_code, int val) +{ + struct cm36651_data *cm36651 = iio_priv(indio_dev); + struct i2c_client *client = cm36651->client; + int ret; + + if (val < 3 || val > 255) + return -EINVAL; + + cm36651->ps_ctrl_regs[CM36651_PS_THD] = val; + ret = i2c_smbus_write_byte_data(cm36651->ps_client, CM36651_PS_THD, + cm36651->ps_ctrl_regs[CM36651_PS_THD]); + + if (ret < 0) { + dev_err(&client->dev, "PS threshold write failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int cm36651_write_prox_event_config(struct iio_dev *indio_dev, + u64 event_code, int state) +{ + struct cm36651_data *cm36651 = iio_priv(indio_dev); + int cmd, ret = -EINVAL; + + mutex_lock(&cm36651->lock); + + cmd = state ? CM36651_CMD_PROX_EV_EN : CM36651_CMD_PROX_EV_DIS; + ret = cm36651_set_operation_mode(cm36651, cmd); + + mutex_unlock(&cm36651->lock); + + return ret; +} + +static int cm36651_read_prox_event_config(struct iio_dev *indio_dev, + u64 event_code) +{ + struct cm36651_data *cm36651 = iio_priv(indio_dev); + int event_en; + + mutex_lock(&cm36651->lock); + + event_en = test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags); + + mutex_unlock(&cm36651->lock); + + return event_en; +} + +#define CM36651_LIGHT_CHANNEL(_color, _idx) { \ + .type = IIO_LIGHT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_INT_TIME), \ + .address = _idx, \ + .modified = 1, \ + .channel2 = IIO_MOD_LIGHT_##_color, \ +} \ + +static const struct iio_chan_spec cm36651_channels[] = { + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME), + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER) + }, + CM36651_LIGHT_CHANNEL(RED, CM36651_LIGHT_CHANNEL_IDX_RED), + CM36651_LIGHT_CHANNEL(GREEN, CM36651_LIGHT_CHANNEL_IDX_GREEN), + CM36651_LIGHT_CHANNEL(BLUE, CM36651_LIGHT_CHANNEL_IDX_BLUE), + CM36651_LIGHT_CHANNEL(CLEAR, CM36651_LIGHT_CHANNEL_IDX_CLEAR), +}; + +static IIO_CONST_ATTR(in_illuminance_integration_time_available, + CM36651_CS_INT_TIME_AVAIL); +static IIO_CONST_ATTR(in_proximity_integration_time_available, + CM36651_PS_INT_TIME_AVAIL); + +static struct attribute *cm36651_attributes[] = { + &iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr, + &iio_const_attr_in_proximity_integration_time_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group cm36651_attribute_group = { + .attrs = cm36651_attributes +}; + +static const struct iio_info cm36651_info = { + .driver_module = THIS_MODULE, + .read_raw = &cm36651_read_raw, + .write_raw = &cm36651_write_raw, + .read_event_value = &cm36651_read_prox_thresh, + .write_event_value = &cm36651_write_prox_thresh, + .read_event_config = &cm36651_read_prox_event_config, + .write_event_config = &cm36651_write_prox_event_config, + .attrs = &cm36651_attribute_group, +}; + +static int cm36651_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cm36651_data *cm36651; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm36651)); + if (!indio_dev) + return -ENOMEM; + + cm36651 = iio_priv(indio_dev); + + cm36651->vled_reg = devm_regulator_get(&client->dev, "vled"); + if (IS_ERR(cm36651->vled_reg)) { + dev_err(&client->dev, "get regulator vled failed\n"); + return PTR_ERR(cm36651->vled_reg); + } + + ret = regulator_enable(cm36651->vled_reg); + if (ret) { + dev_err(&client->dev, "enable regulator vled failed\n"); + return ret; + } + + i2c_set_clientdata(client, indio_dev); + + cm36651->client = client; + cm36651->ps_client = i2c_new_dummy(client->adapter, + CM36651_I2C_ADDR_PS); + cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA); + mutex_init(&cm36651->lock); + indio_dev->dev.parent = &client->dev; + indio_dev->channels = cm36651_channels; + indio_dev->num_channels = ARRAY_SIZE(cm36651_channels); + indio_dev->info = &cm36651_info; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = cm36651_setup_reg(cm36651); + if (ret) { + dev_err(&client->dev, "%s: register setup failed\n", __func__); + goto error_disable_reg; + } + + ret = request_threaded_irq(client->irq, NULL, cm36651_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "cm36651", indio_dev); + if (ret) { + dev_err(&client->dev, "%s: request irq failed\n", __func__); + goto error_disable_reg; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&client->dev, "%s: regist device failed\n", __func__); + goto error_free_irq; + } + + return 0; + +error_free_irq: + free_irq(client->irq, indio_dev); +error_disable_reg: + regulator_disable(cm36651->vled_reg); + return ret; +} + +static int cm36651_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct cm36651_data *cm36651 = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(cm36651->vled_reg); + free_irq(client->irq, indio_dev); + + return 0; +} + +static const struct i2c_device_id cm36651_id[] = { + { "cm36651", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, cm36651_id); + +static const struct of_device_id cm36651_of_match[] = { + { .compatible = "capella,cm36651" }, + { } +}; + +static struct i2c_driver cm36651_driver = { + .driver = { + .name = "cm36651", + .of_match_table = of_match_ptr(cm36651_of_match), + .owner = THIS_MODULE, + }, + .probe = cm36651_probe, + .remove = cm36651_remove, + .id_table = cm36651_id, +}; + +module_i2c_driver(cm36651_driver); + +MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); +MODULE_DESCRIPTION("CM36651 proximity/ambient light sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c new file mode 100644 index 000000000000..dc79835be308 --- /dev/null +++ b/drivers/iio/light/gp2ap020a00f.c @@ -0,0 +1,1654 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Author: Jacek Anaszewski <j.anaszewski@samsung.com> + * + * IIO features supported by the driver: + * + * Read-only raw channels: + * - illiminance_clear [lux] + * - illiminance_ir + * - proximity + * + * Triggered buffer: + * - illiminance_clear + * - illiminance_ir + * - proximity + * + * Events: + * - illuminance_clear (rising and falling) + * - proximity (rising and falling) + * - both falling and rising thresholds for the proximity events + * must be set to the values greater than 0. + * + * The driver supports triggered buffers for all the three + * channels as well as high and low threshold events for the + * illuminance_clear and proxmimity channels. Triggers + * can be enabled simultaneously with both illuminance_clear + * events. Proximity events cannot be enabled simultaneously + * with any triggers or illuminance events. Enabling/disabling + * one of the proximity events automatically enables/disables + * the other one. + * + * 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/debugfs.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irq_work.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define GP2A_I2C_NAME "gp2ap020a00f" + +/* Registers */ +#define GP2AP020A00F_OP_REG 0x00 /* Basic operations */ +#define GP2AP020A00F_ALS_REG 0x01 /* ALS related settings */ +#define GP2AP020A00F_PS_REG 0x02 /* PS related settings */ +#define GP2AP020A00F_LED_REG 0x03 /* LED reg */ +#define GP2AP020A00F_TL_L_REG 0x04 /* ALS: Threshold low LSB */ +#define GP2AP020A00F_TL_H_REG 0x05 /* ALS: Threshold low MSB */ +#define GP2AP020A00F_TH_L_REG 0x06 /* ALS: Threshold high LSB */ +#define GP2AP020A00F_TH_H_REG 0x07 /* ALS: Threshold high MSB */ +#define GP2AP020A00F_PL_L_REG 0x08 /* PS: Threshold low LSB */ +#define GP2AP020A00F_PL_H_REG 0x09 /* PS: Threshold low MSB */ +#define GP2AP020A00F_PH_L_REG 0x0a /* PS: Threshold high LSB */ +#define GP2AP020A00F_PH_H_REG 0x0b /* PS: Threshold high MSB */ +#define GP2AP020A00F_D0_L_REG 0x0c /* ALS result: Clear/Illuminance LSB */ +#define GP2AP020A00F_D0_H_REG 0x0d /* ALS result: Clear/Illuminance MSB */ +#define GP2AP020A00F_D1_L_REG 0x0e /* ALS result: IR LSB */ +#define GP2AP020A00F_D1_H_REG 0x0f /* ALS result: IR LSB */ +#define GP2AP020A00F_D2_L_REG 0x10 /* PS result LSB */ +#define GP2AP020A00F_D2_H_REG 0x11 /* PS result MSB */ +#define GP2AP020A00F_NUM_REGS 0x12 /* Number of registers */ + +/* OP_REG bits */ +#define GP2AP020A00F_OP3_MASK 0x80 /* Software shutdown */ +#define GP2AP020A00F_OP3_SHUTDOWN 0x00 +#define GP2AP020A00F_OP3_OPERATION 0x80 +#define GP2AP020A00F_OP2_MASK 0x40 /* Auto shutdown/Continuous mode */ +#define GP2AP020A00F_OP2_AUTO_SHUTDOWN 0x00 +#define GP2AP020A00F_OP2_CONT_OPERATION 0x40 +#define GP2AP020A00F_OP_MASK 0x30 /* Operating mode selection */ +#define GP2AP020A00F_OP_ALS_AND_PS 0x00 +#define GP2AP020A00F_OP_ALS 0x10 +#define GP2AP020A00F_OP_PS 0x20 +#define GP2AP020A00F_OP_DEBUG 0x30 +#define GP2AP020A00F_PROX_MASK 0x08 /* PS: detection/non-detection */ +#define GP2AP020A00F_PROX_NON_DETECT 0x00 +#define GP2AP020A00F_PROX_DETECT 0x08 +#define GP2AP020A00F_FLAG_P 0x04 /* PS: interrupt result */ +#define GP2AP020A00F_FLAG_A 0x02 /* ALS: interrupt result */ +#define GP2AP020A00F_TYPE_MASK 0x01 /* Output data type selection */ +#define GP2AP020A00F_TYPE_MANUAL_CALC 0x00 +#define GP2AP020A00F_TYPE_AUTO_CALC 0x01 + +/* ALS_REG bits */ +#define GP2AP020A00F_PRST_MASK 0xc0 /* Number of measurement cycles */ +#define GP2AP020A00F_PRST_ONCE 0x00 +#define GP2AP020A00F_PRST_4_CYCLES 0x40 +#define GP2AP020A00F_PRST_8_CYCLES 0x80 +#define GP2AP020A00F_PRST_16_CYCLES 0xc0 +#define GP2AP020A00F_RES_A_MASK 0x38 /* ALS: Resolution */ +#define GP2AP020A00F_RES_A_800ms 0x00 +#define GP2AP020A00F_RES_A_400ms 0x08 +#define GP2AP020A00F_RES_A_200ms 0x10 +#define GP2AP020A00F_RES_A_100ms 0x18 +#define GP2AP020A00F_RES_A_25ms 0x20 +#define GP2AP020A00F_RES_A_6_25ms 0x28 +#define GP2AP020A00F_RES_A_1_56ms 0x30 +#define GP2AP020A00F_RES_A_0_39ms 0x38 +#define GP2AP020A00F_RANGE_A_MASK 0x07 /* ALS: Max measurable range */ +#define GP2AP020A00F_RANGE_A_x1 0x00 +#define GP2AP020A00F_RANGE_A_x2 0x01 +#define GP2AP020A00F_RANGE_A_x4 0x02 +#define GP2AP020A00F_RANGE_A_x8 0x03 +#define GP2AP020A00F_RANGE_A_x16 0x04 +#define GP2AP020A00F_RANGE_A_x32 0x05 +#define GP2AP020A00F_RANGE_A_x64 0x06 +#define GP2AP020A00F_RANGE_A_x128 0x07 + +/* PS_REG bits */ +#define GP2AP020A00F_ALC_MASK 0x80 /* Auto light cancel */ +#define GP2AP020A00F_ALC_ON 0x80 +#define GP2AP020A00F_ALC_OFF 0x00 +#define GP2AP020A00F_INTTYPE_MASK 0x40 /* Interrupt type setting */ +#define GP2AP020A00F_INTTYPE_LEVEL 0x00 +#define GP2AP020A00F_INTTYPE_PULSE 0x40 +#define GP2AP020A00F_RES_P_MASK 0x38 /* PS: Resolution */ +#define GP2AP020A00F_RES_P_800ms_x2 0x00 +#define GP2AP020A00F_RES_P_400ms_x2 0x08 +#define GP2AP020A00F_RES_P_200ms_x2 0x10 +#define GP2AP020A00F_RES_P_100ms_x2 0x18 +#define GP2AP020A00F_RES_P_25ms_x2 0x20 +#define GP2AP020A00F_RES_P_6_25ms_x2 0x28 +#define GP2AP020A00F_RES_P_1_56ms_x2 0x30 +#define GP2AP020A00F_RES_P_0_39ms_x2 0x38 +#define GP2AP020A00F_RANGE_P_MASK 0x07 /* PS: Max measurable range */ +#define GP2AP020A00F_RANGE_P_x1 0x00 +#define GP2AP020A00F_RANGE_P_x2 0x01 +#define GP2AP020A00F_RANGE_P_x4 0x02 +#define GP2AP020A00F_RANGE_P_x8 0x03 +#define GP2AP020A00F_RANGE_P_x16 0x04 +#define GP2AP020A00F_RANGE_P_x32 0x05 +#define GP2AP020A00F_RANGE_P_x64 0x06 +#define GP2AP020A00F_RANGE_P_x128 0x07 + +/* LED reg bits */ +#define GP2AP020A00F_INTVAL_MASK 0xc0 /* Intermittent operating */ +#define GP2AP020A00F_INTVAL_0 0x00 +#define GP2AP020A00F_INTVAL_4 0x40 +#define GP2AP020A00F_INTVAL_8 0x80 +#define GP2AP020A00F_INTVAL_16 0xc0 +#define GP2AP020A00F_IS_MASK 0x30 /* ILED drive peak current */ +#define GP2AP020A00F_IS_13_8mA 0x00 +#define GP2AP020A00F_IS_27_5mA 0x10 +#define GP2AP020A00F_IS_55mA 0x20 +#define GP2AP020A00F_IS_110mA 0x30 +#define GP2AP020A00F_PIN_MASK 0x0c /* INT terminal setting */ +#define GP2AP020A00F_PIN_ALS_OR_PS 0x00 +#define GP2AP020A00F_PIN_ALS 0x04 +#define GP2AP020A00F_PIN_PS 0x08 +#define GP2AP020A00F_PIN_PS_DETECT 0x0c +#define GP2AP020A00F_FREQ_MASK 0x02 /* LED modulation frequency */ +#define GP2AP020A00F_FREQ_327_5kHz 0x00 +#define GP2AP020A00F_FREQ_81_8kHz 0x02 +#define GP2AP020A00F_RST 0x01 /* Software reset */ + +#define GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR 0 +#define GP2AP020A00F_SCAN_MODE_LIGHT_IR 1 +#define GP2AP020A00F_SCAN_MODE_PROXIMITY 2 +#define GP2AP020A00F_CHAN_TIMESTAMP 3 + +#define GP2AP020A00F_DATA_READY_TIMEOUT msecs_to_jiffies(1000) +#define GP2AP020A00F_DATA_REG(chan) (GP2AP020A00F_D0_L_REG + \ + (chan) * 2) +#define GP2AP020A00F_THRESH_REG(th_val_id) (GP2AP020A00F_TL_L_REG + \ + (th_val_id) * 2) +#define GP2AP020A00F_THRESH_VAL_ID(reg_addr) ((reg_addr - 4) / 2) + +#define GP2AP020A00F_SUBTRACT_MODE 0 +#define GP2AP020A00F_ADD_MODE 1 + +#define GP2AP020A00F_MAX_CHANNELS 3 + +enum gp2ap020a00f_opmode { + GP2AP020A00F_OPMODE_READ_RAW_CLEAR, + GP2AP020A00F_OPMODE_READ_RAW_IR, + GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_OPMODE_PS, + GP2AP020A00F_OPMODE_ALS_AND_PS, + GP2AP020A00F_OPMODE_PROX_DETECT, + GP2AP020A00F_OPMODE_SHUTDOWN, + GP2AP020A00F_NUM_OPMODES, +}; + +enum gp2ap020a00f_cmd { + GP2AP020A00F_CMD_READ_RAW_CLEAR, + GP2AP020A00F_CMD_READ_RAW_IR, + GP2AP020A00F_CMD_READ_RAW_PROXIMITY, + GP2AP020A00F_CMD_TRIGGER_CLEAR_EN, + GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS, + GP2AP020A00F_CMD_TRIGGER_IR_EN, + GP2AP020A00F_CMD_TRIGGER_IR_DIS, + GP2AP020A00F_CMD_TRIGGER_PROX_EN, + GP2AP020A00F_CMD_TRIGGER_PROX_DIS, + GP2AP020A00F_CMD_ALS_HIGH_EV_EN, + GP2AP020A00F_CMD_ALS_HIGH_EV_DIS, + GP2AP020A00F_CMD_ALS_LOW_EV_EN, + GP2AP020A00F_CMD_ALS_LOW_EV_DIS, + GP2AP020A00F_CMD_PROX_HIGH_EV_EN, + GP2AP020A00F_CMD_PROX_HIGH_EV_DIS, + GP2AP020A00F_CMD_PROX_LOW_EV_EN, + GP2AP020A00F_CMD_PROX_LOW_EV_DIS, +}; + +enum gp2ap020a00f_flags { + GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, + GP2AP020A00F_FLAG_ALS_IR_TRIGGER, + GP2AP020A00F_FLAG_PROX_TRIGGER, + GP2AP020A00F_FLAG_PROX_RISING_EV, + GP2AP020A00F_FLAG_PROX_FALLING_EV, + GP2AP020A00F_FLAG_ALS_RISING_EV, + GP2AP020A00F_FLAG_ALS_FALLING_EV, + GP2AP020A00F_FLAG_LUX_MODE_HI, + GP2AP020A00F_FLAG_DATA_READY, +}; + +enum gp2ap020a00f_thresh_val_id { + GP2AP020A00F_THRESH_TL, + GP2AP020A00F_THRESH_TH, + GP2AP020A00F_THRESH_PL, + GP2AP020A00F_THRESH_PH, +}; + +struct gp2ap020a00f_data { + const struct gp2ap020a00f_platform_data *pdata; + struct i2c_client *client; + struct mutex lock; + char *buffer; + struct regulator *vled_reg; + unsigned long flags; + enum gp2ap020a00f_opmode cur_opmode; + struct iio_trigger *trig; + struct regmap *regmap; + unsigned int thresh_val[4]; + u8 debug_reg_addr; + struct irq_work work; + wait_queue_head_t data_ready_queue; +}; + +static const u8 gp2ap020a00f_reg_init_tab[] = { + [GP2AP020A00F_OP_REG] = GP2AP020A00F_OP3_SHUTDOWN, + [GP2AP020A00F_ALS_REG] = GP2AP020A00F_RES_A_25ms | + GP2AP020A00F_RANGE_A_x8, + [GP2AP020A00F_PS_REG] = GP2AP020A00F_ALC_ON | + GP2AP020A00F_RES_P_1_56ms_x2 | + GP2AP020A00F_RANGE_P_x4, + [GP2AP020A00F_LED_REG] = GP2AP020A00F_INTVAL_0 | + GP2AP020A00F_IS_110mA | + GP2AP020A00F_FREQ_327_5kHz, + [GP2AP020A00F_TL_L_REG] = 0, + [GP2AP020A00F_TL_H_REG] = 0, + [GP2AP020A00F_TH_L_REG] = 0, + [GP2AP020A00F_TH_H_REG] = 0, + [GP2AP020A00F_PL_L_REG] = 0, + [GP2AP020A00F_PL_H_REG] = 0, + [GP2AP020A00F_PH_L_REG] = 0, + [GP2AP020A00F_PH_H_REG] = 0, +}; + +static bool gp2ap020a00f_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case GP2AP020A00F_OP_REG: + case GP2AP020A00F_D0_L_REG: + case GP2AP020A00F_D0_H_REG: + case GP2AP020A00F_D1_L_REG: + case GP2AP020A00F_D1_H_REG: + case GP2AP020A00F_D2_L_REG: + case GP2AP020A00F_D2_H_REG: + return true; + default: + return false; + } +} + +static const struct regmap_config gp2ap020a00f_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = GP2AP020A00F_D2_H_REG, + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = gp2ap020a00f_is_volatile_reg, +}; + +static const struct gp2ap020a00f_mutable_config_regs { + u8 op_reg; + u8 als_reg; + u8 ps_reg; + u8 led_reg; +} opmode_regs_settings[GP2AP020A00F_NUM_OPMODES] = { + [GP2AP020A00F_OPMODE_READ_RAW_CLEAR] = { + GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_AUTO_CALC, + GP2AP020A00F_PRST_ONCE, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_ALS + }, + [GP2AP020A00F_OPMODE_READ_RAW_IR] = { + GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_MANUAL_CALC, + GP2AP020A00F_PRST_ONCE, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_ALS + }, + [GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY] = { + GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_MANUAL_CALC, + GP2AP020A00F_PRST_ONCE, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_PS + }, + [GP2AP020A00F_OPMODE_PROX_DETECT] = { + GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_MANUAL_CALC, + GP2AP020A00F_PRST_4_CYCLES, + GP2AP020A00F_INTTYPE_PULSE, + GP2AP020A00F_PIN_PS_DETECT + }, + [GP2AP020A00F_OPMODE_ALS] = { + GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_AUTO_CALC, + GP2AP020A00F_PRST_ONCE, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_ALS + }, + [GP2AP020A00F_OPMODE_PS] = { + GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_MANUAL_CALC, + GP2AP020A00F_PRST_4_CYCLES, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_PS + }, + [GP2AP020A00F_OPMODE_ALS_AND_PS] = { + GP2AP020A00F_OP_ALS_AND_PS + | GP2AP020A00F_OP2_CONT_OPERATION + | GP2AP020A00F_OP3_OPERATION + | GP2AP020A00F_TYPE_AUTO_CALC, + GP2AP020A00F_PRST_4_CYCLES, + GP2AP020A00F_INTTYPE_LEVEL, + GP2AP020A00F_PIN_ALS_OR_PS + }, + [GP2AP020A00F_OPMODE_SHUTDOWN] = { GP2AP020A00F_OP3_SHUTDOWN, }, +}; + +static int gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data *data, + enum gp2ap020a00f_opmode op) +{ + unsigned int op_reg_val; + int err; + + if (op != GP2AP020A00F_OPMODE_SHUTDOWN) { + err = regmap_read(data->regmap, GP2AP020A00F_OP_REG, + &op_reg_val); + if (err < 0) + return err; + /* + * Shutdown the device if the operation being executed entails + * mode transition. + */ + if ((opmode_regs_settings[op].op_reg & GP2AP020A00F_OP_MASK) != + (op_reg_val & GP2AP020A00F_OP_MASK)) { + /* set shutdown mode */ + err = regmap_update_bits(data->regmap, + GP2AP020A00F_OP_REG, GP2AP020A00F_OP3_MASK, + GP2AP020A00F_OP3_SHUTDOWN); + if (err < 0) + return err; + } + + err = regmap_update_bits(data->regmap, GP2AP020A00F_ALS_REG, + GP2AP020A00F_PRST_MASK, opmode_regs_settings[op] + .als_reg); + if (err < 0) + return err; + + err = regmap_update_bits(data->regmap, GP2AP020A00F_PS_REG, + GP2AP020A00F_INTTYPE_MASK, opmode_regs_settings[op] + .ps_reg); + if (err < 0) + return err; + + err = regmap_update_bits(data->regmap, GP2AP020A00F_LED_REG, + GP2AP020A00F_PIN_MASK, opmode_regs_settings[op] + .led_reg); + if (err < 0) + return err; + } + + /* Set OP_REG and apply operation mode (power on / off) */ + err = regmap_update_bits(data->regmap, + GP2AP020A00F_OP_REG, + GP2AP020A00F_OP_MASK | GP2AP020A00F_OP2_MASK | + GP2AP020A00F_OP3_MASK | GP2AP020A00F_TYPE_MASK, + opmode_regs_settings[op].op_reg); + if (err < 0) + return err; + + data->cur_opmode = op; + + return 0; +} + +static bool gp2ap020a00f_als_enabled(struct gp2ap020a00f_data *data) +{ + return test_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags) || + test_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags) || + test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags) || + test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); +} + +static bool gp2ap020a00f_prox_detect_enabled(struct gp2ap020a00f_data *data) +{ + return test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags) || + test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); +} + +static int gp2ap020a00f_write_event_threshold(struct gp2ap020a00f_data *data, + enum gp2ap020a00f_thresh_val_id th_val_id, + bool enable) +{ + __le16 thresh_buf = 0; + unsigned int thresh_reg_val; + + if (!enable) + thresh_reg_val = 0; + else if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags) && + th_val_id != GP2AP020A00F_THRESH_PL && + th_val_id != GP2AP020A00F_THRESH_PH) + /* + * For the high lux mode ALS threshold has to be scaled down + * to allow for proper comparison with the output value. + */ + thresh_reg_val = data->thresh_val[th_val_id] / 16; + else + thresh_reg_val = data->thresh_val[th_val_id] > 16000 ? + 16000 : + data->thresh_val[th_val_id]; + + thresh_buf = cpu_to_le16(thresh_reg_val); + + return regmap_bulk_write(data->regmap, + GP2AP020A00F_THRESH_REG(th_val_id), + (u8 *)&thresh_buf, 2); +} + +static int gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data *data, + enum gp2ap020a00f_opmode diff_mode, int add_sub) +{ + enum gp2ap020a00f_opmode new_mode; + + if (diff_mode != GP2AP020A00F_OPMODE_ALS && + diff_mode != GP2AP020A00F_OPMODE_PS) + return -EINVAL; + + if (add_sub == GP2AP020A00F_ADD_MODE) { + if (data->cur_opmode == GP2AP020A00F_OPMODE_SHUTDOWN) + new_mode = diff_mode; + else + new_mode = GP2AP020A00F_OPMODE_ALS_AND_PS; + } else { + if (data->cur_opmode == GP2AP020A00F_OPMODE_ALS_AND_PS) + new_mode = (diff_mode == GP2AP020A00F_OPMODE_ALS) ? + GP2AP020A00F_OPMODE_PS : + GP2AP020A00F_OPMODE_ALS; + else + new_mode = GP2AP020A00F_OPMODE_SHUTDOWN; + } + + return gp2ap020a00f_set_operation_mode(data, new_mode); +} + +static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, + enum gp2ap020a00f_cmd cmd) +{ + int err = 0; + + switch (cmd) { + case GP2AP020A00F_CMD_READ_RAW_CLEAR: + if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) + return -EBUSY; + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_READ_RAW_CLEAR); + break; + case GP2AP020A00F_CMD_READ_RAW_IR: + if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) + return -EBUSY; + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_READ_RAW_IR); + break; + case GP2AP020A00F_CMD_READ_RAW_PROXIMITY: + if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) + return -EBUSY; + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY); + break; + case GP2AP020A00F_CMD_TRIGGER_CLEAR_EN: + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + if (!gp2ap020a00f_als_enabled(data)) + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_ADD_MODE); + set_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags); + break; + case GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS: + clear_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags); + if (gp2ap020a00f_als_enabled(data)) + break; + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_SUBTRACT_MODE); + break; + case GP2AP020A00F_CMD_TRIGGER_IR_EN: + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + if (!gp2ap020a00f_als_enabled(data)) + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_ADD_MODE); + set_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags); + break; + case GP2AP020A00F_CMD_TRIGGER_IR_DIS: + clear_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags); + if (gp2ap020a00f_als_enabled(data)) + break; + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_SUBTRACT_MODE); + break; + case GP2AP020A00F_CMD_TRIGGER_PROX_EN: + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_PS, + GP2AP020A00F_ADD_MODE); + set_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags); + break; + case GP2AP020A00F_CMD_TRIGGER_PROX_DIS: + clear_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags); + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_PS, + GP2AP020A00F_SUBTRACT_MODE); + break; + case GP2AP020A00F_CMD_ALS_HIGH_EV_EN: + if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) + return 0; + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + if (!gp2ap020a00f_als_enabled(data)) { + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_ADD_MODE); + if (err < 0) + return err; + } + set_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags); + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TH, true); + break; + case GP2AP020A00F_CMD_ALS_HIGH_EV_DIS: + if (!test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) + return 0; + clear_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags); + if (!gp2ap020a00f_als_enabled(data)) { + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_SUBTRACT_MODE); + if (err < 0) + return err; + } + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TH, false); + break; + case GP2AP020A00F_CMD_ALS_LOW_EV_EN: + if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) + return 0; + if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) + return -EBUSY; + if (!gp2ap020a00f_als_enabled(data)) { + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_ADD_MODE); + if (err < 0) + return err; + } + set_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TL, true); + break; + case GP2AP020A00F_CMD_ALS_LOW_EV_DIS: + if (!test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) + return 0; + clear_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); + if (!gp2ap020a00f_als_enabled(data)) { + err = gp2ap020a00f_alter_opmode(data, + GP2AP020A00F_OPMODE_ALS, + GP2AP020A00F_SUBTRACT_MODE); + if (err < 0) + return err; + } + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TL, false); + break; + case GP2AP020A00F_CMD_PROX_HIGH_EV_EN: + if (test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags)) + return 0; + if (gp2ap020a00f_als_enabled(data) || + data->cur_opmode == GP2AP020A00F_OPMODE_PS) + return -EBUSY; + if (!gp2ap020a00f_prox_detect_enabled(data)) { + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_PROX_DETECT); + if (err < 0) + return err; + } + set_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags); + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_PH, true); + break; + case GP2AP020A00F_CMD_PROX_HIGH_EV_DIS: + if (!test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags)) + return 0; + clear_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags); + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_SHUTDOWN); + if (err < 0) + return err; + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_PH, false); + break; + case GP2AP020A00F_CMD_PROX_LOW_EV_EN: + if (test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags)) + return 0; + if (gp2ap020a00f_als_enabled(data) || + data->cur_opmode == GP2AP020A00F_OPMODE_PS) + return -EBUSY; + if (!gp2ap020a00f_prox_detect_enabled(data)) { + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_PROX_DETECT); + if (err < 0) + return err; + } + set_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_PL, true); + break; + case GP2AP020A00F_CMD_PROX_LOW_EV_DIS: + if (!test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags)) + return 0; + clear_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_SHUTDOWN); + if (err < 0) + return err; + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_PL, false); + break; + } + + return err; +} + +static int wait_conversion_complete_irq(struct gp2ap020a00f_data *data) +{ + int ret; + + ret = wait_event_timeout(data->data_ready_queue, + test_bit(GP2AP020A00F_FLAG_DATA_READY, + &data->flags), + GP2AP020A00F_DATA_READY_TIMEOUT); + clear_bit(GP2AP020A00F_FLAG_DATA_READY, &data->flags); + + return ret > 0 ? 0 : -ETIME; +} + +static int gp2ap020a00f_read_output(struct gp2ap020a00f_data *data, + unsigned int output_reg, int *val) +{ + u8 reg_buf[2]; + int err; + + err = wait_conversion_complete_irq(data); + if (err < 0) + dev_dbg(&data->client->dev, "data ready timeout\n"); + + err = regmap_bulk_read(data->regmap, output_reg, reg_buf, 2); + if (err < 0) + return err; + + *val = le16_to_cpup((__le16 *)reg_buf); + + return err; +} + +static bool gp2ap020a00f_adjust_lux_mode(struct gp2ap020a00f_data *data, + int output_val) +{ + u8 new_range = 0xff; + int err; + + if (!test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags)) { + if (output_val > 16000) { + set_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags); + new_range = GP2AP020A00F_RANGE_A_x128; + } + } else { + if (output_val < 1000) { + clear_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags); + new_range = GP2AP020A00F_RANGE_A_x8; + } + } + + if (new_range != 0xff) { + /* Clear als threshold registers to avoid spurious + * events caused by lux mode transition. + */ + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TH, false); + if (err < 0) { + dev_err(&data->client->dev, + "Clearing als threshold register failed.\n"); + return false; + } + + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TL, false); + if (err < 0) { + dev_err(&data->client->dev, + "Clearing als threshold register failed.\n"); + return false; + } + + /* Change lux mode */ + err = regmap_update_bits(data->regmap, + GP2AP020A00F_OP_REG, + GP2AP020A00F_OP3_MASK, + GP2AP020A00F_OP3_SHUTDOWN); + + if (err < 0) { + dev_err(&data->client->dev, + "Shutting down the device failed.\n"); + return false; + } + + err = regmap_update_bits(data->regmap, + GP2AP020A00F_ALS_REG, + GP2AP020A00F_RANGE_A_MASK, + new_range); + + if (err < 0) { + dev_err(&data->client->dev, + "Adjusting device lux mode failed.\n"); + return false; + } + + err = regmap_update_bits(data->regmap, + GP2AP020A00F_OP_REG, + GP2AP020A00F_OP3_MASK, + GP2AP020A00F_OP3_OPERATION); + + if (err < 0) { + dev_err(&data->client->dev, + "Powering up the device failed.\n"); + return false; + } + + /* Adjust als threshold register values to the new lux mode */ + if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) { + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TH, true); + if (err < 0) { + dev_err(&data->client->dev, + "Adjusting als threshold value failed.\n"); + return false; + } + } + + if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) { + err = gp2ap020a00f_write_event_threshold(data, + GP2AP020A00F_THRESH_TL, true); + if (err < 0) { + dev_err(&data->client->dev, + "Adjusting als threshold value failed.\n"); + return false; + } + } + + return true; + } + + return false; +} + +static void gp2ap020a00f_output_to_lux(struct gp2ap020a00f_data *data, + int *output_val) +{ + if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags)) + *output_val *= 16; +} + +static void gp2ap020a00f_iio_trigger_work(struct irq_work *work) +{ + struct gp2ap020a00f_data *data = + container_of(work, struct gp2ap020a00f_data, work); + + iio_trigger_poll(data->trig, 0); +} + +static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct gp2ap020a00f_data *priv = iio_priv(indio_dev); + unsigned int op_reg_val; + int ret; + + /* Read interrupt flags */ + ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, &op_reg_val); + if (ret < 0) + return IRQ_HANDLED; + + if (gp2ap020a00f_prox_detect_enabled(priv)) { + if (op_reg_val & GP2AP020A00F_PROX_DETECT) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE( + IIO_PROXIMITY, + GP2AP020A00F_SCAN_MODE_PROXIMITY, + IIO_EV_TYPE_ROC, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + } else { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE( + IIO_PROXIMITY, + GP2AP020A00F_SCAN_MODE_PROXIMITY, + IIO_EV_TYPE_ROC, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct gp2ap020a00f_data *priv = iio_priv(indio_dev); + u8 op_reg_flags, d0_reg_buf[2]; + unsigned int output_val, op_reg_val; + int thresh_val_id, ret; + + /* Read interrupt flags */ + ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, + &op_reg_val); + if (ret < 0) + goto done; + + op_reg_flags = op_reg_val & (GP2AP020A00F_FLAG_A | GP2AP020A00F_FLAG_P + | GP2AP020A00F_PROX_DETECT); + + op_reg_val &= (~GP2AP020A00F_FLAG_A & ~GP2AP020A00F_FLAG_P + & ~GP2AP020A00F_PROX_DETECT); + + /* Clear interrupt flags (if not in INTTYPE_PULSE mode) */ + if (priv->cur_opmode != GP2AP020A00F_OPMODE_PROX_DETECT) { + ret = regmap_write(priv->regmap, GP2AP020A00F_OP_REG, + op_reg_val); + if (ret < 0) + goto done; + } + + if (op_reg_flags & GP2AP020A00F_FLAG_A) { + /* Check D0 register to assess if the lux mode + * transition is required. + */ + ret = regmap_bulk_read(priv->regmap, GP2AP020A00F_D0_L_REG, + d0_reg_buf, 2); + if (ret < 0) + goto done; + + output_val = le16_to_cpup((__le16 *)d0_reg_buf); + + if (gp2ap020a00f_adjust_lux_mode(priv, output_val)) + goto done; + + gp2ap020a00f_output_to_lux(priv, &output_val); + + /* + * We need to check output value to distinguish + * between high and low ambient light threshold event. + */ + if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &priv->flags)) { + thresh_val_id = + GP2AP020A00F_THRESH_VAL_ID(GP2AP020A00F_TH_L_REG); + if (output_val > priv->thresh_val[thresh_val_id]) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE( + IIO_LIGHT, + GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR, + IIO_MOD_LIGHT_CLEAR, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + } + + if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &priv->flags)) { + thresh_val_id = + GP2AP020A00F_THRESH_VAL_ID(GP2AP020A00F_TL_L_REG); + if (output_val < priv->thresh_val[thresh_val_id]) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE( + IIO_LIGHT, + GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR, + IIO_MOD_LIGHT_CLEAR, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } + } + + if (priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_CLEAR || + priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_IR || + priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY) { + set_bit(GP2AP020A00F_FLAG_DATA_READY, &priv->flags); + wake_up(&priv->data_ready_queue); + goto done; + } + + if (test_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &priv->flags) || + test_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &priv->flags) || + test_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &priv->flags)) + /* This fires off the trigger. */ + irq_work_queue(&priv->work); + +done: + return IRQ_HANDLED; +} + +static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data) +{ + struct iio_poll_func *pf = data; + struct iio_dev *indio_dev = pf->indio_dev; + struct gp2ap020a00f_data *priv = iio_priv(indio_dev); + size_t d_size = 0; + __le32 light_lux; + int i, out_val, ret; + + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = regmap_bulk_read(priv->regmap, + GP2AP020A00F_DATA_REG(i), + &priv->buffer[d_size], 2); + if (ret < 0) + goto done; + + if (i == GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR || + i == GP2AP020A00F_SCAN_MODE_LIGHT_IR) { + out_val = le16_to_cpup((__le16 *)&priv->buffer[d_size]); + gp2ap020a00f_output_to_lux(priv, &out_val); + light_lux = cpu_to_le32(out_val); + memcpy(&priv->buffer[d_size], (u8 *)&light_lux, 4); + d_size += 4; + } else { + d_size += 2; + } + } + + iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer, + pf->timestamp); +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static u8 gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan, + enum iio_event_direction event_dir) +{ + switch (chan->type) { + case IIO_PROXIMITY: + if (event_dir == IIO_EV_DIR_RISING) + return GP2AP020A00F_PH_L_REG; + else + return GP2AP020A00F_PL_L_REG; + case IIO_LIGHT: + if (event_dir == IIO_EV_DIR_RISING) + return GP2AP020A00F_TH_L_REG; + else + return GP2AP020A00F_TL_L_REG; + default: + break; + } + + return -EINVAL; +} + +static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + bool event_en = false; + u8 thresh_val_id; + u8 thresh_reg_l; + int err = 0; + + mutex_lock(&data->lock); + + thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir); + thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l); + + if (thresh_val_id > GP2AP020A00F_THRESH_PH) { + err = -EINVAL; + goto error_unlock; + } + + switch (thresh_reg_l) { + case GP2AP020A00F_TH_L_REG: + event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, + &data->flags); + break; + case GP2AP020A00F_TL_L_REG: + event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, + &data->flags); + break; + case GP2AP020A00F_PH_L_REG: + if (val == 0) { + err = -EINVAL; + goto error_unlock; + } + event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, + &data->flags); + break; + case GP2AP020A00F_PL_L_REG: + if (val == 0) { + err = -EINVAL; + goto error_unlock; + } + event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, + &data->flags); + break; + } + + data->thresh_val[thresh_val_id] = val; + err = gp2ap020a00f_write_event_threshold(data, thresh_val_id, + event_en); +error_unlock: + mutex_unlock(&data->lock); + + return err; +} + +static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + u8 thresh_reg_l; + int err = IIO_VAL_INT; + + mutex_lock(&data->lock); + + thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir); + + if (thresh_reg_l > GP2AP020A00F_PH_L_REG) { + err = -EINVAL; + goto error_unlock; + } + + *val = data->thresh_val[GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l)]; + +error_unlock: + mutex_unlock(&data->lock); + + return err; +} + +static int gp2ap020a00f_write_prox_event_config(struct iio_dev *indio_dev, + int state) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + enum gp2ap020a00f_cmd cmd_high_ev, cmd_low_ev; + int err; + + cmd_high_ev = state ? GP2AP020A00F_CMD_PROX_HIGH_EV_EN : + GP2AP020A00F_CMD_PROX_HIGH_EV_DIS; + cmd_low_ev = state ? GP2AP020A00F_CMD_PROX_LOW_EV_EN : + GP2AP020A00F_CMD_PROX_LOW_EV_DIS; + + /* + * In order to enable proximity detection feature in the device + * both high and low threshold registers have to be written + * with different values, greater than zero. + */ + if (state) { + if (data->thresh_val[GP2AP020A00F_THRESH_PL] == 0) + return -EINVAL; + + if (data->thresh_val[GP2AP020A00F_THRESH_PH] == 0) + return -EINVAL; + } + + err = gp2ap020a00f_exec_cmd(data, cmd_high_ev); + if (err < 0) + return err; + + err = gp2ap020a00f_exec_cmd(data, cmd_low_ev); + if (err < 0) + return err; + + free_irq(data->client->irq, indio_dev); + + if (state) + err = request_threaded_irq(data->client->irq, NULL, + &gp2ap020a00f_prox_sensing_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "gp2ap020a00f_prox_sensing", + indio_dev); + else { + err = request_threaded_irq(data->client->irq, NULL, + &gp2ap020a00f_thresh_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "gp2ap020a00f_thresh_event", + indio_dev); + } + + return err; +} + +static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + enum gp2ap020a00f_cmd cmd; + int err; + + mutex_lock(&data->lock); + + switch (chan->type) { + case IIO_PROXIMITY: + err = gp2ap020a00f_write_prox_event_config(indio_dev, state); + break; + case IIO_LIGHT: + if (dir == IIO_EV_DIR_RISING) { + cmd = state ? GP2AP020A00F_CMD_ALS_HIGH_EV_EN : + GP2AP020A00F_CMD_ALS_HIGH_EV_DIS; + err = gp2ap020a00f_exec_cmd(data, cmd); + } else { + cmd = state ? GP2AP020A00F_CMD_ALS_LOW_EV_EN : + GP2AP020A00F_CMD_ALS_LOW_EV_DIS; + err = gp2ap020a00f_exec_cmd(data, cmd); + } + break; + default: + err = -EINVAL; + } + + mutex_unlock(&data->lock); + + return err; +} + +static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int event_en = 0; + + mutex_lock(&data->lock); + + switch (chan->type) { + case IIO_PROXIMITY: + if (dir == IIO_EV_DIR_RISING) + event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, + &data->flags); + else + event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, + &data->flags); + break; + case IIO_LIGHT: + if (dir == IIO_EV_DIR_RISING) + event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, + &data->flags); + else + event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, + &data->flags); + break; + default: + event_en = -EINVAL; + break; + } + + mutex_unlock(&data->lock); + + return event_en; +} + +static int gp2ap020a00f_read_channel(struct gp2ap020a00f_data *data, + struct iio_chan_spec const *chan, int *val) +{ + enum gp2ap020a00f_cmd cmd; + int err; + + switch (chan->scan_index) { + case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR: + cmd = GP2AP020A00F_CMD_READ_RAW_CLEAR; + break; + case GP2AP020A00F_SCAN_MODE_LIGHT_IR: + cmd = GP2AP020A00F_CMD_READ_RAW_IR; + break; + case GP2AP020A00F_SCAN_MODE_PROXIMITY: + cmd = GP2AP020A00F_CMD_READ_RAW_PROXIMITY; + break; + default: + return -EINVAL; + } + + err = gp2ap020a00f_exec_cmd(data, cmd); + if (err < 0) { + dev_err(&data->client->dev, + "gp2ap020a00f_exec_cmd failed\n"); + goto error_ret; + } + + err = gp2ap020a00f_read_output(data, chan->address, val); + if (err < 0) + dev_err(&data->client->dev, + "gp2ap020a00f_read_output failed\n"); + + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_SHUTDOWN); + if (err < 0) + dev_err(&data->client->dev, + "Failed to shut down the device.\n"); + + if (cmd == GP2AP020A00F_CMD_READ_RAW_CLEAR || + cmd == GP2AP020A00F_CMD_READ_RAW_IR) + gp2ap020a00f_output_to_lux(data, val); + +error_ret: + return err; +} + +static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int err = -EINVAL; + + mutex_lock(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) { + err = -EBUSY; + goto error_unlock; + } + + err = gp2ap020a00f_read_channel(data, chan, val); + break; + } + +error_unlock: + mutex_unlock(&data->lock); + + return err < 0 ? err : IIO_VAL_INT; +} + +static const struct iio_event_spec gp2ap020a00f_event_spec_light[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_event_spec gp2ap020a00f_event_spec_prox[] = { + { + .type = IIO_EV_TYPE_ROC, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_ROC, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_chan_spec gp2ap020a00f_channels[] = { + { + .type = IIO_LIGHT, + .channel2 = IIO_MOD_LIGHT_CLEAR, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .scan_type = { + .sign = 'u', + .realbits = 24, + .shift = 0, + .storagebits = 32, + .endianness = IIO_LE, + }, + .scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR, + .address = GP2AP020A00F_D0_L_REG, + .event_spec = gp2ap020a00f_event_spec_light, + .num_event_specs = ARRAY_SIZE(gp2ap020a00f_event_spec_light), + }, + { + .type = IIO_LIGHT, + .channel2 = IIO_MOD_LIGHT_IR, + .modified = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .scan_type = { + .sign = 'u', + .realbits = 24, + .shift = 0, + .storagebits = 32, + .endianness = IIO_LE, + }, + .scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_IR, + .address = GP2AP020A00F_D1_L_REG, + }, + { + .type = IIO_PROXIMITY, + .modified = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .scan_type = { + .sign = 'u', + .realbits = 16, + .shift = 0, + .storagebits = 16, + .endianness = IIO_LE, + }, + .scan_index = GP2AP020A00F_SCAN_MODE_PROXIMITY, + .address = GP2AP020A00F_D2_L_REG, + .event_spec = gp2ap020a00f_event_spec_prox, + .num_event_specs = ARRAY_SIZE(gp2ap020a00f_event_spec_prox), + }, + IIO_CHAN_SOFT_TIMESTAMP(GP2AP020A00F_CHAN_TIMESTAMP), +}; + +static const struct iio_info gp2ap020a00f_info = { + .read_raw = &gp2ap020a00f_read_raw, + .read_event_value_new = &gp2ap020a00f_read_event_val, + .read_event_config_new = &gp2ap020a00f_read_event_config, + .write_event_value_new = &gp2ap020a00f_write_event_val, + .write_event_config_new = &gp2ap020a00f_write_event_config, + .driver_module = THIS_MODULE, +}; + +static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int i, err = 0; + + mutex_lock(&data->lock); + + /* + * Enable triggers according to the scan_mask. Enabling either + * LIGHT_CLEAR or LIGHT_IR scan mode results in enabling ALS + * module in the device, which generates samples in both D0 (clear) + * and D1 (ir) registers. As the two registers are bound to the + * two separate IIO channels they are treated in the driver logic + * as if they were controlled independently. + */ + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + switch (i) { + case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_CLEAR_EN); + break; + case GP2AP020A00F_SCAN_MODE_LIGHT_IR: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_IR_EN); + break; + case GP2AP020A00F_SCAN_MODE_PROXIMITY: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_PROX_EN); + break; + } + } + + if (err < 0) + goto error_unlock; + + data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); + if (!data->buffer) { + err = -ENOMEM; + goto error_unlock; + } + + err = iio_triggered_buffer_postenable(indio_dev); + +error_unlock: + mutex_unlock(&data->lock); + + return err; +} + +static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev) +{ + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int i, err; + + mutex_lock(&data->lock); + + err = iio_triggered_buffer_predisable(indio_dev); + if (err < 0) + goto error_unlock; + + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + switch (i) { + case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS); + break; + case GP2AP020A00F_SCAN_MODE_LIGHT_IR: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_IR_DIS); + break; + case GP2AP020A00F_SCAN_MODE_PROXIMITY: + err = gp2ap020a00f_exec_cmd(data, + GP2AP020A00F_CMD_TRIGGER_PROX_DIS); + break; + } + } + + if (err == 0) + kfree(data->buffer); + +error_unlock: + mutex_unlock(&data->lock); + + return err; +} + +static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = { + .postenable = &gp2ap020a00f_buffer_postenable, + .predisable = &gp2ap020a00f_buffer_predisable, +}; + +static const struct iio_trigger_ops gp2ap020a00f_trigger_ops = { + .owner = THIS_MODULE, +}; + +static int gp2ap020a00f_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct gp2ap020a00f_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + int err; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + + data->vled_reg = devm_regulator_get(&client->dev, "vled"); + if (IS_ERR(data->vled_reg)) + return PTR_ERR(data->vled_reg); + + err = regulator_enable(data->vled_reg); + if (err) + return err; + + regmap = devm_regmap_init_i2c(client, &gp2ap020a00f_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Regmap initialization failed.\n"); + err = PTR_ERR(regmap); + goto error_regulator_disable; + } + + /* Initialize device registers */ + err = regmap_bulk_write(regmap, GP2AP020A00F_OP_REG, + gp2ap020a00f_reg_init_tab, + ARRAY_SIZE(gp2ap020a00f_reg_init_tab)); + + if (err < 0) { + dev_err(&client->dev, "Device initialization failed.\n"); + goto error_regulator_disable; + } + + i2c_set_clientdata(client, indio_dev); + + data->client = client; + data->cur_opmode = GP2AP020A00F_OPMODE_SHUTDOWN; + data->regmap = regmap; + init_waitqueue_head(&data->data_ready_queue); + + mutex_init(&data->lock); + indio_dev->dev.parent = &client->dev; + indio_dev->channels = gp2ap020a00f_channels; + indio_dev->num_channels = ARRAY_SIZE(gp2ap020a00f_channels); + indio_dev->info = &gp2ap020a00f_info; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + + /* Allocate buffer */ + err = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &gp2ap020a00f_trigger_handler, &gp2ap020a00f_buffer_setup_ops); + if (err < 0) + goto error_regulator_disable; + + /* Allocate trigger */ + data->trig = devm_iio_trigger_alloc(&client->dev, "%s-trigger", + indio_dev->name); + if (data->trig == NULL) { + err = -ENOMEM; + dev_err(&indio_dev->dev, "Failed to allocate iio trigger.\n"); + goto error_uninit_buffer; + } + + /* This needs to be requested here for read_raw calls to work. */ + err = request_threaded_irq(client->irq, NULL, + &gp2ap020a00f_thresh_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "gp2ap020a00f_als_event", + indio_dev); + if (err < 0) { + dev_err(&client->dev, "Irq request failed.\n"); + goto error_uninit_buffer; + } + + data->trig->ops = &gp2ap020a00f_trigger_ops; + data->trig->dev.parent = &data->client->dev; + + init_irq_work(&data->work, gp2ap020a00f_iio_trigger_work); + + err = iio_trigger_register(data->trig); + if (err < 0) { + dev_err(&client->dev, "Failed to register iio trigger.\n"); + goto error_free_irq; + } + + err = iio_device_register(indio_dev); + if (err < 0) + goto error_trigger_unregister; + + return 0; + +error_trigger_unregister: + iio_trigger_unregister(data->trig); +error_free_irq: + free_irq(client->irq, indio_dev); +error_uninit_buffer: + iio_triggered_buffer_cleanup(indio_dev); +error_regulator_disable: + regulator_disable(data->vled_reg); + + return err; +} + +static int gp2ap020a00f_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct gp2ap020a00f_data *data = iio_priv(indio_dev); + int err; + + err = gp2ap020a00f_set_operation_mode(data, + GP2AP020A00F_OPMODE_SHUTDOWN); + if (err < 0) + dev_err(&indio_dev->dev, "Failed to power off the device.\n"); + + iio_device_unregister(indio_dev); + iio_trigger_unregister(data->trig); + free_irq(client->irq, indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(data->vled_reg); + + return 0; +} + +static const struct i2c_device_id gp2ap020a00f_id[] = { + { GP2A_I2C_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id); + +#ifdef CONFIG_OF +static const struct of_device_id gp2ap020a00f_of_match[] = { + { .compatible = "sharp,gp2ap020a00f" }, + { } +}; +#endif + +static struct i2c_driver gp2ap020a00f_driver = { + .driver = { + .name = GP2A_I2C_NAME, + .of_match_table = of_match_ptr(gp2ap020a00f_of_match), + .owner = THIS_MODULE, + }, + .probe = gp2ap020a00f_probe, + .remove = gp2ap020a00f_remove, + .id_table = gp2ap020a00f_id, +}; + +module_i2c_driver(gp2ap020a00f_driver); + +MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); +MODULE_DESCRIPTION("Sharp GP2AP020A00F Proximity/ALS sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index e59d00c3139c..fa6ae8cf89ea 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -161,10 +161,11 @@ static const struct iio_info als_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -179,7 +180,7 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev, als_state->common_attributes.data_ready); if (als_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - (u8 *)&als_state->illum, + &als_state->illum, sizeof(als_state->illum)); return 0; diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c new file mode 100644 index 000000000000..45df2204614a --- /dev/null +++ b/drivers/iio/light/tcs3472.c @@ -0,0 +1,367 @@ +/* + * tcs3472.c - Support for TAOS TCS3472 color light-to-digital converter + * + * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net> + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * Color light sensor with 16-bit channels for red, green, blue, clear); + * 7-bit I2C slave address 0x39 (TCS34721, TCS34723) or 0x29 (TCS34725, + * TCS34727) + * + * TODO: interrupt support, thresholds, wait time + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/pm.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/buffer.h> +#include <linux/iio/triggered_buffer.h> + +#define TCS3472_DRV_NAME "tcs3472" + +#define TCS3472_COMMAND BIT(7) +#define TCS3472_AUTO_INCR BIT(5) + +#define TCS3472_ENABLE (TCS3472_COMMAND | 0x00) +#define TCS3472_ATIME (TCS3472_COMMAND | 0x01) +#define TCS3472_WTIME (TCS3472_COMMAND | 0x03) +#define TCS3472_AILT (TCS3472_COMMAND | 0x04) +#define TCS3472_AIHT (TCS3472_COMMAND | 0x06) +#define TCS3472_PERS (TCS3472_COMMAND | 0x0c) +#define TCS3472_CONFIG (TCS3472_COMMAND | 0x0d) +#define TCS3472_CONTROL (TCS3472_COMMAND | 0x0f) +#define TCS3472_ID (TCS3472_COMMAND | 0x12) +#define TCS3472_STATUS (TCS3472_COMMAND | 0x13) +#define TCS3472_CDATA (TCS3472_COMMAND | TCS3472_AUTO_INCR | 0x14) +#define TCS3472_RDATA (TCS3472_COMMAND | TCS3472_AUTO_INCR | 0x16) +#define TCS3472_GDATA (TCS3472_COMMAND | TCS3472_AUTO_INCR | 0x18) +#define TCS3472_BDATA (TCS3472_COMMAND | TCS3472_AUTO_INCR | 0x1a) + +#define TCS3472_STATUS_AVALID BIT(0) +#define TCS3472_ENABLE_AEN BIT(1) +#define TCS3472_ENABLE_PON BIT(0) +#define TCS3472_CONTROL_AGAIN_MASK (BIT(0) | BIT(1)) + +struct tcs3472_data { + struct i2c_client *client; + u8 enable; + u8 control; + u8 atime; + u16 buffer[8]; /* 4 16-bit channels + 64-bit timestamp */ +}; + +#define TCS3472_CHANNEL(_color, _si, _addr) { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_INT_TIME), \ + .channel2 = IIO_MOD_LIGHT_##_color, \ + .address = _addr, \ + .scan_index = _si, \ + .scan_type = IIO_ST('u', 16, 16, 0), \ +} + +static const int tcs3472_agains[] = { 1, 4, 16, 60 }; + +static const struct iio_chan_spec tcs3472_channels[] = { + TCS3472_CHANNEL(CLEAR, 0, TCS3472_CDATA), + TCS3472_CHANNEL(RED, 1, TCS3472_RDATA), + TCS3472_CHANNEL(GREEN, 2, TCS3472_GDATA), + TCS3472_CHANNEL(BLUE, 3, TCS3472_BDATA), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static int tcs3472_req_data(struct tcs3472_data *data) +{ + int tries = 50; + int ret; + + while (tries--) { + ret = i2c_smbus_read_byte_data(data->client, TCS3472_STATUS); + if (ret < 0) + return ret; + if (ret & TCS3472_STATUS_AVALID) + break; + msleep(20); + } + + if (tries < 0) { + dev_err(&data->client->dev, "data not ready\n"); + return -EIO; + } + + return 0; +} + +static int tcs3472_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct tcs3472_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = tcs3472_req_data(data); + if (ret < 0) + return ret; + ret = i2c_smbus_read_word_data(data->client, chan->address); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + *val = tcs3472_agains[data->control & + TCS3472_CONTROL_AGAIN_MASK]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = (256 - data->atime) * 2400; + return IIO_VAL_INT_PLUS_MICRO; + } + return -EINVAL; +} + +static int tcs3472_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct tcs3472_data *data = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + if (val2 != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(tcs3472_agains); i++) { + if (val == tcs3472_agains[i]) { + data->control &= ~TCS3472_CONTROL_AGAIN_MASK; + data->control |= i; + return i2c_smbus_write_byte_data( + data->client, TCS3472_CONTROL, + data->control); + } + } + return -EINVAL; + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + for (i = 0; i < 256; i++) { + if (val2 == (256 - i) * 2400) { + data->atime = i; + return i2c_smbus_write_word_data( + data->client, TCS3472_ATIME, + data->atime); + } + + } + return -EINVAL; + } + return -EINVAL; +} + +static irqreturn_t tcs3472_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct tcs3472_data *data = iio_priv(indio_dev); + int len = 0; + int i, j = 0; + + int ret = tcs3472_req_data(data); + if (ret < 0) + goto done; + + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = i2c_smbus_read_word_data(data->client, + TCS3472_CDATA + 2*i); + if (ret < 0) + goto done; + + data->buffer[j++] = ret; + len += 2; + } + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_get_time_ns()); + +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static ssize_t tcs3472_show_int_time_available(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + size_t len = 0; + int i; + + for (i = 1; i <= 256; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06d ", + 2400 * i); + + /* replace trailing space by newline */ + buf[len - 1] = '\n'; + + return len; +} + +static IIO_CONST_ATTR(calibscale_available, "1 4 16 60"); +static IIO_DEV_ATTR_INT_TIME_AVAIL(tcs3472_show_int_time_available); + +static struct attribute *tcs3472_attributes[] = { + &iio_const_attr_calibscale_available.dev_attr.attr, + &iio_dev_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group tcs3472_attribute_group = { + .attrs = tcs3472_attributes, +}; + +static const struct iio_info tcs3472_info = { + .read_raw = tcs3472_read_raw, + .write_raw = tcs3472_write_raw, + .attrs = &tcs3472_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int tcs3472_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tcs3472_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &tcs3472_info; + indio_dev->name = TCS3472_DRV_NAME; + indio_dev->channels = tcs3472_channels; + indio_dev->num_channels = ARRAY_SIZE(tcs3472_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_ID); + if (ret < 0) + return ret; + + if (ret == 0x44) + dev_info(&client->dev, "TCS34721/34725 found\n"); + else if (ret == 0x4d) + dev_info(&client->dev, "TCS34723/34727 found\n"); + else + return -ENODEV; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONTROL); + if (ret < 0) + return ret; + data->control = ret; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_ATIME); + if (ret < 0) + return ret; + data->atime = ret; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_ENABLE); + if (ret < 0) + return ret; + + /* enable device */ + data->enable = ret | TCS3472_ENABLE_PON | TCS3472_ENABLE_AEN; + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + data->enable); + if (ret < 0) + return ret; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + tcs3472_trigger_handler, NULL); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto buffer_cleanup; + + return 0; + +buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + return ret; +} + +static int tcs3472_powerdown(struct tcs3472_data *data) +{ + return i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + data->enable & ~(TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON)); +} + +static int tcs3472_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + tcs3472_powerdown(iio_priv(indio_dev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tcs3472_suspend(struct device *dev) +{ + struct tcs3472_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return tcs3472_powerdown(data); +} + +static int tcs3472_resume(struct device *dev) +{ + struct tcs3472_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + data->enable | (TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON)); +} +#endif + +static SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, tcs3472_resume); + +static const struct i2c_device_id tcs3472_id[] = { + { "tcs3472", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tcs3472_id); + +static struct i2c_driver tcs3472_driver = { + .driver = { + .name = TCS3472_DRV_NAME, + .pm = &tcs3472_pm_ops, + .owner = THIS_MODULE, + }, + .probe = tcs3472_probe, + .remove = tcs3472_remove, + .id_table = tcs3472_id, +}; +module_i2c_driver(tcs3472_driver); + +MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); +MODULE_DESCRIPTION("TCS3472 color light sensors driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index ebb962c5c323..5e5d9dea22c5 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -526,6 +526,20 @@ error_ret: return ret; } +static const struct iio_event_spec tsl2563_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + static const struct iio_chan_spec tsl2563_channels[] = { { .type = IIO_LIGHT, @@ -538,10 +552,8 @@ static const struct iio_chan_spec tsl2563_channels[] = { .channel2 = IIO_MOD_LIGHT_BOTH, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING)), + .event_spec = tsl2563_events, + .num_event_specs = ARRAY_SIZE(tsl2563_events), }, { .type = IIO_INTENSITY, .modified = 1, @@ -552,12 +564,13 @@ static const struct iio_chan_spec tsl2563_channels[] = { }; static int tsl2563_read_thresh(struct iio_dev *indio_dev, - u64 event_code, - int *val) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, int *val, + int *val2) { struct tsl2563_chip *chip = iio_priv(indio_dev); - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + switch (dir) { case IIO_EV_DIR_RISING: *val = chip->high_thres; break; @@ -568,18 +581,19 @@ static int tsl2563_read_thresh(struct iio_dev *indio_dev, return -EINVAL; } - return 0; + return IIO_VAL_INT; } static int tsl2563_write_thresh(struct iio_dev *indio_dev, - u64 event_code, - int val) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, int val, + int val2) { struct tsl2563_chip *chip = iio_priv(indio_dev); int ret; u8 address; - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING) + if (dir == IIO_EV_DIR_RISING) address = TSL2563_REG_HIGHLOW; else address = TSL2563_REG_LOWLOW; @@ -591,7 +605,7 @@ static int tsl2563_write_thresh(struct iio_dev *indio_dev, ret = i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | (address + 1), (val >> 8) & 0xFF); - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING) + if (dir == IIO_EV_DIR_RISING) chip->high_thres = val; else chip->low_thres = val; @@ -620,8 +634,8 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private) } static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev, - u64 event_code, - int state) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) { struct tsl2563_chip *chip = iio_priv(indio_dev); int ret = 0; @@ -662,7 +676,8 @@ out: } static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) { struct tsl2563_chip *chip = iio_priv(indio_dev); int ret; @@ -687,10 +702,10 @@ static const struct iio_info tsl2563_info = { .driver_module = THIS_MODULE, .read_raw = &tsl2563_read_raw, .write_raw = &tsl2563_write_raw, - .read_event_value = &tsl2563_read_thresh, - .write_event_value = &tsl2563_write_thresh, - .read_event_config = &tsl2563_read_interrupt_config, - .write_event_config = &tsl2563_write_interrupt_config, + .read_event_value_new = &tsl2563_read_thresh, + .write_event_value_new = &tsl2563_write_thresh, + .read_event_config_new = &tsl2563_read_interrupt_config, + .write_event_config_new = &tsl2563_write_interrupt_config, }; static int tsl2563_probe(struct i2c_client *client, diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c new file mode 100644 index 000000000000..a15006efa137 --- /dev/null +++ b/drivers/iio/light/tsl4531.c @@ -0,0 +1,258 @@ +/* + * tsl4531.c - Support for TAOS TSL4531 ambient light sensor + * + * Copyright 2013 Peter Meerwald <pmeerw@pmeerw.net> + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * IIO driver for the TSL4531x family + * TSL45311/TSL45313: 7-bit I2C slave address 0x39 + * TSL45315/TSL45317: 7-bit I2C slave address 0x29 + * + * TODO: single cycle measurement + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/delay.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#define TSL4531_DRV_NAME "tsl4531" + +#define TCS3472_COMMAND BIT(7) + +#define TSL4531_CONTROL (TCS3472_COMMAND | 0x00) +#define TSL4531_CONFIG (TCS3472_COMMAND | 0x01) +#define TSL4531_DATA (TCS3472_COMMAND | 0x04) +#define TSL4531_ID (TCS3472_COMMAND | 0x0a) + +/* operating modes in control register */ +#define TSL4531_MODE_POWERDOWN 0x00 +#define TSL4531_MODE_SINGLE_ADC 0x02 +#define TSL4531_MODE_NORMAL 0x03 + +/* integration time control in config register */ +#define TSL4531_TCNTRL_400MS 0x00 +#define TSL4531_TCNTRL_200MS 0x01 +#define TSL4531_TCNTRL_100MS 0x02 + +/* part number in id register */ +#define TSL45311_ID 0x8 +#define TSL45313_ID 0x9 +#define TSL45315_ID 0xa +#define TSL45317_ID 0xb +#define TSL4531_ID_SHIFT 4 + +struct tsl4531_data { + struct i2c_client *client; + struct mutex lock; + int int_time; +}; + +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.2 0.4"); + +static struct attribute *tsl4531_attributes[] = { + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group tsl4531_attribute_group = { + .attrs = tsl4531_attributes, +}; + +static const struct iio_chan_spec tsl4531_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_INT_TIME) + } +}; + +static int tsl4531_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct tsl4531_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_word_data(data->client, + TSL4531_DATA); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* 0.. 1x, 1 .. 2x, 2 .. 4x */ + *val = 1 << data->int_time; + return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + if (data->int_time == 0) + *val2 = 400000; + else if (data->int_time == 1) + *val2 = 200000; + else if (data->int_time == 2) + *val2 = 100000; + else + return -EINVAL; + *val = 0; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int tsl4531_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct tsl4531_data *data = iio_priv(indio_dev); + int int_time, ret; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + if (val2 == 400000) + int_time = 0; + else if (val2 == 200000) + int_time = 1; + else if (val2 == 100000) + int_time = 2; + else + return -EINVAL; + mutex_lock(&data->lock); + ret = i2c_smbus_write_byte_data(data->client, + TSL4531_CONFIG, int_time); + if (ret >= 0) + data->int_time = int_time; + mutex_unlock(&data->lock); + return ret; + default: + return -EINVAL; + } +} + +static const struct iio_info tsl4531_info = { + .read_raw = tsl4531_read_raw, + .write_raw = tsl4531_write_raw, + .attrs = &tsl4531_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int tsl4531_check_id(struct i2c_client *client) +{ + int ret = i2c_smbus_read_byte_data(client, TSL4531_ID); + if (ret < 0) + return ret; + + switch (ret >> TSL4531_ID_SHIFT) { + case TSL45311_ID: + case TSL45313_ID: + case TSL45315_ID: + case TSL45317_ID: + return 1; + default: + return 0; + } +} + +static int tsl4531_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tsl4531_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); + + if (!tsl4531_check_id(client)) { + dev_err(&client->dev, "no TSL4531 sensor\n"); + return -ENODEV; + } + + ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL, + TSL4531_MODE_NORMAL); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONFIG, + TSL4531_TCNTRL_400MS); + if (ret < 0) + return ret; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &tsl4531_info; + indio_dev->channels = tsl4531_channels; + indio_dev->num_channels = ARRAY_SIZE(tsl4531_channels); + indio_dev->name = TSL4531_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + + return iio_device_register(indio_dev); +} + +static int tsl4531_powerdown(struct i2c_client *client) +{ + return i2c_smbus_write_byte_data(client, TSL4531_CONTROL, + TSL4531_MODE_POWERDOWN); +} + +static int tsl4531_remove(struct i2c_client *client) +{ + iio_device_unregister(i2c_get_clientdata(client)); + tsl4531_powerdown(client); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tsl4531_suspend(struct device *dev) +{ + return tsl4531_powerdown(to_i2c_client(dev)); +} + +static int tsl4531_resume(struct device *dev) +{ + return i2c_smbus_write_byte_data(to_i2c_client(dev), TSL4531_CONTROL, + TSL4531_MODE_NORMAL); +} +#endif + +static SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume); + +static const struct i2c_device_id tsl4531_id[] = { + { "tsl4531", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tsl4531_id); + +static struct i2c_driver tsl4531_driver = { + .driver = { + .name = TSL4531_DRV_NAME, + .pm = &tsl4531_pm_ops, + .owner = THIS_MODULE, + }, + .probe = tsl4531_probe, + .remove = tsl4531_remove, + .id_table = tsl4531_id, +}; + +module_i2c_driver(tsl4531_driver); + +MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); +MODULE_DESCRIPTION("TAOS TSL4531 ambient light sensors 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 a98460b15e4b..2634920562fb 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -183,10 +183,11 @@ static const struct iio_info magn_3d_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -201,7 +202,7 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, magn_state->common_attributes.data_ready); if (magn_state->common_attributes.data_ready) hid_sensor_push_data(indio_dev, - (u8 *)magn_state->magn_val, + magn_state->magn_val, sizeof(magn_state->magn_val)); return 0; diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index 708857bdb47d..bf427dc0d226 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -25,16 +25,7 @@ static int st_magn_buffer_preenable(struct iio_dev *indio_dev) { - int err; - - err = st_sensors_set_enable(indio_dev, true); - if (err < 0) - goto st_magn_set_enable_error; - - err = iio_sw_buffer_preenable(indio_dev); - -st_magn_set_enable_error: - return err; + return st_sensors_set_enable(indio_dev, true); } static int st_magn_buffer_postenable(struct iio_dev *indio_dev) diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index cab3bc7494a2..52bbcfa1e077 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -348,8 +348,9 @@ static const struct iio_info magn_info = { int st_magn_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) { - int err; struct st_sensor_data *mdata = iio_priv(indio_dev); + int irq = mdata->get_irq_data_ready(indio_dev); + int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &magn_info; @@ -357,7 +358,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev, err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_magn_sensors), st_magn_sensors); if (err < 0) - goto st_magn_common_probe_error; + return err; mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; mdata->multiread_bit = mdata->sensor->multi_read_bit; @@ -370,12 +371,13 @@ int st_magn_common_probe(struct iio_dev *indio_dev, err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_magn_common_probe_error; + return err; - if (mdata->get_irq_data_ready(indio_dev) > 0) { - err = st_magn_allocate_ring(indio_dev); - if (err < 0) - goto st_magn_common_probe_error; + err = st_magn_allocate_ring(indio_dev); + if (err < 0) + return err; + + if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, NULL); if (err < 0) goto st_magn_probe_trigger_error; @@ -385,15 +387,14 @@ int st_magn_common_probe(struct iio_dev *indio_dev, if (err) goto st_magn_device_register_error; - return err; + return 0; st_magn_device_register_error: - if (mdata->get_irq_data_ready(indio_dev) > 0) + if (irq > 0) st_sensors_deallocate_trigger(indio_dev); st_magn_probe_trigger_error: - if (mdata->get_irq_data_ready(indio_dev) > 0) - st_magn_deallocate_ring(indio_dev); -st_magn_common_probe_error: + st_magn_deallocate_ring(indio_dev); + return err; } EXPORT_SYMBOL(st_magn_common_probe); @@ -403,10 +404,10 @@ void st_magn_common_remove(struct iio_dev *indio_dev) struct st_sensor_data *mdata = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (mdata->get_irq_data_ready(indio_dev) > 0) { + if (mdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); - st_magn_deallocate_ring(indio_dev); - } + + st_magn_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_magn_common_remove); diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index b0b630688da6..049c21acf1f0 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/iio/common/st_sensors.h> +#define LPS001WP_PRESS_DEV_NAME "lps001wp" #define LPS331AP_PRESS_DEV_NAME "lps331ap" /** diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c index f877ef8af520..b37b1c9ac932 100644 --- a/drivers/iio/pressure/st_pressure_buffer.c +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -32,16 +32,7 @@ int st_press_trig_set_state(struct iio_trigger *trig, bool state) static int st_press_buffer_preenable(struct iio_dev *indio_dev) { - int err; - - err = st_sensors_set_enable(indio_dev, true); - if (err < 0) - goto st_press_set_enable_error; - - err = iio_sw_buffer_preenable(indio_dev); - -st_press_set_enable_error: - return err; + return st_sensors_set_enable(indio_dev, true); } static int st_press_buffer_postenable(struct iio_dev *indio_dev) diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index ceebd3c27892..58083f9d51c5 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -23,6 +23,7 @@ #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> #include <linux/iio/buffer.h> +#include <linux/regulator/consumer.h> #include <asm/unaligned.h> #include <linux/iio/common/st_sensors.h> @@ -36,94 +37,200 @@ ST_PRESS_LSB_PER_CELSIUS) #define ST_PRESS_NUMBER_DATA_CHANNELS 1 -/* DEFAULT VALUE FOR SENSORS */ -#define ST_PRESS_DEFAULT_OUT_XL_ADDR 0x28 -#define ST_TEMP_DEFAULT_OUT_L_ADDR 0x2b - /* FULLSCALE */ #define ST_PRESS_FS_AVL_1260MB 1260 -/* CUSTOM VALUES FOR SENSOR 1 */ -#define ST_PRESS_1_WAI_EXP 0xbb -#define ST_PRESS_1_ODR_ADDR 0x20 -#define ST_PRESS_1_ODR_MASK 0x70 -#define ST_PRESS_1_ODR_AVL_1HZ_VAL 0x01 -#define ST_PRESS_1_ODR_AVL_7HZ_VAL 0x05 -#define ST_PRESS_1_ODR_AVL_13HZ_VAL 0x06 -#define ST_PRESS_1_ODR_AVL_25HZ_VAL 0x07 -#define ST_PRESS_1_PW_ADDR 0x20 -#define ST_PRESS_1_PW_MASK 0x80 -#define ST_PRESS_1_FS_ADDR 0x23 -#define ST_PRESS_1_FS_MASK 0x30 -#define ST_PRESS_1_FS_AVL_1260_VAL 0x00 -#define ST_PRESS_1_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE -#define ST_PRESS_1_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE -#define ST_PRESS_1_BDU_ADDR 0x20 -#define ST_PRESS_1_BDU_MASK 0x04 -#define ST_PRESS_1_DRDY_IRQ_ADDR 0x22 -#define ST_PRESS_1_DRDY_IRQ_INT1_MASK 0x04 -#define ST_PRESS_1_DRDY_IRQ_INT2_MASK 0x20 -#define ST_PRESS_1_MULTIREAD_BIT true -#define ST_PRESS_1_TEMP_OFFSET 42500 - -static const struct iio_chan_spec st_press_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_PRESSURE, +/* CUSTOM VALUES FOR LPS331AP SENSOR */ +#define ST_PRESS_LPS331AP_WAI_EXP 0xbb +#define ST_PRESS_LPS331AP_ODR_ADDR 0x20 +#define ST_PRESS_LPS331AP_ODR_MASK 0x70 +#define ST_PRESS_LPS331AP_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_LPS331AP_ODR_AVL_7HZ_VAL 0x05 +#define ST_PRESS_LPS331AP_ODR_AVL_13HZ_VAL 0x06 +#define ST_PRESS_LPS331AP_ODR_AVL_25HZ_VAL 0x07 +#define ST_PRESS_LPS331AP_PW_ADDR 0x20 +#define ST_PRESS_LPS331AP_PW_MASK 0x80 +#define ST_PRESS_LPS331AP_FS_ADDR 0x23 +#define ST_PRESS_LPS331AP_FS_MASK 0x30 +#define ST_PRESS_LPS331AP_FS_AVL_1260_VAL 0x00 +#define ST_PRESS_LPS331AP_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE +#define ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE +#define ST_PRESS_LPS331AP_BDU_ADDR 0x20 +#define ST_PRESS_LPS331AP_BDU_MASK 0x04 +#define ST_PRESS_LPS331AP_DRDY_IRQ_ADDR 0x22 +#define ST_PRESS_LPS331AP_DRDY_IRQ_INT1_MASK 0x04 +#define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK 0x20 +#define ST_PRESS_LPS331AP_MULTIREAD_BIT true +#define ST_PRESS_LPS331AP_TEMP_OFFSET 42500 +#define ST_PRESS_LPS331AP_OUT_XL_ADDR 0x28 +#define ST_TEMP_LPS331AP_OUT_L_ADDR 0x2b + +/* CUSTOM VALUES FOR LPS001WP SENSOR */ +#define ST_PRESS_LPS001WP_WAI_EXP 0xba +#define ST_PRESS_LPS001WP_ODR_ADDR 0x20 +#define ST_PRESS_LPS001WP_ODR_MASK 0x30 +#define ST_PRESS_LPS001WP_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_LPS001WP_ODR_AVL_7HZ_VAL 0x02 +#define ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL 0x03 +#define ST_PRESS_LPS001WP_PW_ADDR 0x20 +#define ST_PRESS_LPS001WP_PW_MASK 0x40 +#define ST_PRESS_LPS001WP_BDU_ADDR 0x20 +#define ST_PRESS_LPS001WP_BDU_MASK 0x04 +#define ST_PRESS_LPS001WP_MULTIREAD_BIT true +#define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28 +#define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a + +static const struct iio_chan_spec st_press_lps331ap_channels[] = { + { + .type = IIO_PRESSURE, + .channel2 = IIO_NO_MOD, + .address = ST_PRESS_LPS331AP_OUT_XL_ADDR, + .scan_index = ST_SENSORS_SCAN_X, + .scan_type = { + .sign = 'u', + .realbits = 24, + .storagebits = 24, + .endianness = IIO_LE, + }, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - ST_SENSORS_SCAN_X, 0, IIO_NO_MOD, 'u', IIO_LE, 24, 24, - ST_PRESS_DEFAULT_OUT_XL_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_TEMP, - BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_OFFSET), - -1, 0, IIO_NO_MOD, 's', IIO_LE, 16, 16, - ST_TEMP_DEFAULT_OUT_L_ADDR), + .modified = 0, + }, + { + .type = IIO_TEMP, + .channel2 = IIO_NO_MOD, + .address = ST_TEMP_LPS331AP_OUT_L_ADDR, + .scan_index = -1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .modified = 0, + }, + IIO_CHAN_SOFT_TIMESTAMP(1) +}; + +static const struct iio_chan_spec st_press_lps001wp_channels[] = { + { + .type = IIO_PRESSURE, + .channel2 = IIO_NO_MOD, + .address = ST_PRESS_LPS001WP_OUT_L_ADDR, + .scan_index = ST_SENSORS_SCAN_X, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .modified = 0, + }, + { + .type = IIO_TEMP, + .channel2 = IIO_NO_MOD, + .address = ST_TEMP_LPS001WP_OUT_L_ADDR, + .scan_index = -1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET), + .modified = 0, + }, IIO_CHAN_SOFT_TIMESTAMP(1) }; static const struct st_sensors st_press_sensors[] = { { - .wai = ST_PRESS_1_WAI_EXP, + .wai = ST_PRESS_LPS331AP_WAI_EXP, .sensors_supported = { [0] = LPS331AP_PRESS_DEV_NAME, }, - .ch = (struct iio_chan_spec *)st_press_channels, + .ch = (struct iio_chan_spec *)st_press_lps331ap_channels, + .num_ch = ARRAY_SIZE(st_press_lps331ap_channels), .odr = { - .addr = ST_PRESS_1_ODR_ADDR, - .mask = ST_PRESS_1_ODR_MASK, + .addr = ST_PRESS_LPS331AP_ODR_ADDR, + .mask = ST_PRESS_LPS331AP_ODR_MASK, .odr_avl = { - { 1, ST_PRESS_1_ODR_AVL_1HZ_VAL, }, - { 7, ST_PRESS_1_ODR_AVL_7HZ_VAL, }, - { 13, ST_PRESS_1_ODR_AVL_13HZ_VAL, }, - { 25, ST_PRESS_1_ODR_AVL_25HZ_VAL, }, + { 1, ST_PRESS_LPS331AP_ODR_AVL_1HZ_VAL, }, + { 7, ST_PRESS_LPS331AP_ODR_AVL_7HZ_VAL, }, + { 13, ST_PRESS_LPS331AP_ODR_AVL_13HZ_VAL, }, + { 25, ST_PRESS_LPS331AP_ODR_AVL_25HZ_VAL, }, }, }, .pw = { - .addr = ST_PRESS_1_PW_ADDR, - .mask = ST_PRESS_1_PW_MASK, + .addr = ST_PRESS_LPS331AP_PW_ADDR, + .mask = ST_PRESS_LPS331AP_PW_MASK, .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, .fs = { - .addr = ST_PRESS_1_FS_ADDR, - .mask = ST_PRESS_1_FS_MASK, + .addr = ST_PRESS_LPS331AP_FS_ADDR, + .mask = ST_PRESS_LPS331AP_FS_MASK, .fs_avl = { [0] = { .num = ST_PRESS_FS_AVL_1260MB, - .value = ST_PRESS_1_FS_AVL_1260_VAL, - .gain = ST_PRESS_1_FS_AVL_1260_GAIN, - .gain2 = ST_PRESS_1_FS_AVL_TEMP_GAIN, + .value = ST_PRESS_LPS331AP_FS_AVL_1260_VAL, + .gain = ST_PRESS_LPS331AP_FS_AVL_1260_GAIN, + .gain2 = ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN, }, }, }, .bdu = { - .addr = ST_PRESS_1_BDU_ADDR, - .mask = ST_PRESS_1_BDU_MASK, + .addr = ST_PRESS_LPS331AP_BDU_ADDR, + .mask = ST_PRESS_LPS331AP_BDU_MASK, }, .drdy_irq = { - .addr = ST_PRESS_1_DRDY_IRQ_ADDR, - .mask_int1 = ST_PRESS_1_DRDY_IRQ_INT1_MASK, - .mask_int2 = ST_PRESS_1_DRDY_IRQ_INT2_MASK, + .addr = ST_PRESS_LPS331AP_DRDY_IRQ_ADDR, + .mask_int1 = ST_PRESS_LPS331AP_DRDY_IRQ_INT1_MASK, + .mask_int2 = ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK, }, - .multi_read_bit = ST_PRESS_1_MULTIREAD_BIT, + .multi_read_bit = ST_PRESS_LPS331AP_MULTIREAD_BIT, + .bootime = 2, + }, + { + .wai = ST_PRESS_LPS001WP_WAI_EXP, + .sensors_supported = { + [0] = LPS001WP_PRESS_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_press_lps001wp_channels, + .num_ch = ARRAY_SIZE(st_press_lps001wp_channels), + .odr = { + .addr = ST_PRESS_LPS001WP_ODR_ADDR, + .mask = ST_PRESS_LPS001WP_ODR_MASK, + .odr_avl = { + { 1, ST_PRESS_LPS001WP_ODR_AVL_1HZ_VAL, }, + { 7, ST_PRESS_LPS001WP_ODR_AVL_7HZ_VAL, }, + { 13, ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_PRESS_LPS001WP_PW_ADDR, + .mask = ST_PRESS_LPS001WP_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .fs = { + .addr = 0, + }, + .bdu = { + .addr = ST_PRESS_LPS001WP_BDU_ADDR, + .mask = ST_PRESS_LPS001WP_BDU_MASK, + }, + .drdy_irq = { + .addr = 0, + }, + .multi_read_bit = ST_PRESS_LPS001WP_MULTIREAD_BIT, .bootime = 2, }, }; @@ -207,44 +314,85 @@ static const struct iio_trigger_ops st_press_trigger_ops = { #define ST_PRESS_TRIGGER_OPS NULL #endif +static void st_press_power_enable(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + int err; + + /* Regulators not mandatory, but if requested we should enable them. */ + pdata->vdd = devm_regulator_get_optional(&indio_dev->dev, "vdd"); + if (!IS_ERR(pdata->vdd)) { + err = regulator_enable(pdata->vdd); + if (err != 0) + dev_warn(&indio_dev->dev, + "Failed to enable specified Vdd supply\n"); + } + + pdata->vdd_io = devm_regulator_get_optional(&indio_dev->dev, "vddio"); + if (!IS_ERR(pdata->vdd_io)) { + err = regulator_enable(pdata->vdd_io); + if (err != 0) + dev_warn(&indio_dev->dev, + "Failed to enable specified Vdd_IO supply\n"); + } +} + +static void st_press_power_disable(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + + if (!IS_ERR(pdata->vdd)) + regulator_disable(pdata->vdd); + + if (!IS_ERR(pdata->vdd_io)) + regulator_disable(pdata->vdd_io); +} + int st_press_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *plat_data) { - int err; struct st_sensor_data *pdata = iio_priv(indio_dev); + int irq = pdata->get_irq_data_ready(indio_dev); + int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; + st_press_power_enable(indio_dev); + err = st_sensors_check_device_support(indio_dev, - ARRAY_SIZE(st_press_sensors), st_press_sensors); + ARRAY_SIZE(st_press_sensors), + st_press_sensors); if (err < 0) - goto st_press_common_probe_error; + return err; pdata->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; - pdata->multiread_bit = pdata->sensor->multi_read_bit; - indio_dev->channels = pdata->sensor->ch; - indio_dev->num_channels = ARRAY_SIZE(st_press_channels); + pdata->multiread_bit = pdata->sensor->multi_read_bit; + indio_dev->channels = pdata->sensor->ch; + indio_dev->num_channels = pdata->sensor->num_ch; + + if (pdata->sensor->fs.addr != 0) + pdata->current_fullscale = (struct st_sensor_fullscale_avl *) + &pdata->sensor->fs.fs_avl[0]; - pdata->current_fullscale = (struct st_sensor_fullscale_avl *) - &pdata->sensor->fs.fs_avl[0]; pdata->odr = pdata->sensor->odr.odr_avl[0].hz; - if (!plat_data) + /* Some devices don't support a data ready pin. */ + if (!plat_data && pdata->sensor->drdy_irq.addr) plat_data = (struct st_sensors_platform_data *)&default_press_pdata; err = st_sensors_init_sensor(indio_dev, plat_data); if (err < 0) - goto st_press_common_probe_error; + return err; - if (pdata->get_irq_data_ready(indio_dev) > 0) { - err = st_press_allocate_ring(indio_dev); - if (err < 0) - goto st_press_common_probe_error; + err = st_press_allocate_ring(indio_dev); + if (err < 0) + return err; + if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, - ST_PRESS_TRIGGER_OPS); + ST_PRESS_TRIGGER_OPS); if (err < 0) goto st_press_probe_trigger_error; } @@ -256,12 +404,11 @@ int st_press_common_probe(struct iio_dev *indio_dev, return err; st_press_device_register_error: - if (pdata->get_irq_data_ready(indio_dev) > 0) + if (irq > 0) st_sensors_deallocate_trigger(indio_dev); st_press_probe_trigger_error: - if (pdata->get_irq_data_ready(indio_dev) > 0) - st_press_deallocate_ring(indio_dev); -st_press_common_probe_error: + st_press_deallocate_ring(indio_dev); + return err; } EXPORT_SYMBOL(st_press_common_probe); @@ -270,11 +417,13 @@ void st_press_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *pdata = iio_priv(indio_dev); + st_press_power_disable(indio_dev); + iio_device_unregister(indio_dev); - if (pdata->get_irq_data_ready(indio_dev) > 0) { + if (pdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); - st_press_deallocate_ring(indio_dev); - } + + st_press_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_press_common_remove); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 08aac5e6251d..51eab7fcb194 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -49,6 +49,7 @@ static int st_press_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id st_press_id_table[] = { + { LPS001WP_PRESS_DEV_NAME }, { LPS331AP_PRESS_DEV_NAME }, {}, }; diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index 6d63883da1ab..84a0789c3d96 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -70,12 +70,16 @@ static int tmp006_read_measurement(struct tmp006_data *data, u8 reg) return i2c_smbus_read_word_swapped(data->client, reg); } +static const int tmp006_freqs[5][2] = { {4, 0}, {2, 0}, {1, 0}, + {0, 500000}, {0, 250000} }; + static int tmp006_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask) { struct tmp006_data *data = iio_priv(indio_dev); s32 ret; + int cr; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -106,6 +110,12 @@ static int tmp006_read_raw(struct iio_dev *indio_dev, break; } return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + cr = (data->config & TMP006_CONFIG_CR_MASK) + >> TMP006_CONFIG_CR_SHIFT; + *val = tmp006_freqs[cr][0]; + *val2 = tmp006_freqs[cr][1]; + return IIO_VAL_INT_PLUS_MICRO; default: break; } @@ -113,48 +123,32 @@ static int tmp006_read_raw(struct iio_dev *indio_dev, return -EINVAL; } -static const char * const tmp006_freqs[] = { "4", "2", "1", "0.5", "0.25" }; - -static ssize_t tmp006_show_freq(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev)); - int cr = (data->config & TMP006_CONFIG_CR_MASK) - >> TMP006_CONFIG_CR_SHIFT; - return sprintf(buf, "%s\n", tmp006_freqs[cr]); -} - -static ssize_t tmp006_store_freq(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static int tmp006_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tmp006_data *data = iio_priv(indio_dev); int i; - bool found = false; for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++) - if (sysfs_streq(buf, tmp006_freqs[i])) { - found = true; - break; - } - if (!found) - return -EINVAL; + if ((val == tmp006_freqs[i][0]) && + (val2 == tmp006_freqs[i][1])) { + data->config &= ~TMP006_CONFIG_CR_MASK; + data->config |= i << TMP006_CONFIG_CR_SHIFT; - data->config &= ~TMP006_CONFIG_CR_MASK; - data->config |= i << TMP006_CONFIG_CR_SHIFT; + return i2c_smbus_write_word_swapped(data->client, + TMP006_CONFIG, + data->config); - return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, - data->config); + } + return -EINVAL; } -static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, - tmp006_show_freq, tmp006_store_freq); - static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25"); static struct attribute *tmp006_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL }; @@ -168,16 +162,19 @@ static const struct iio_chan_spec tmp006_channels[] = { .type = IIO_VOLTAGE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), } }; static const struct iio_info tmp006_info = { .read_raw = tmp006_read_raw, + .write_raw = tmp006_write_raw, .attrs = &tmp006_attribute_group, .driver_module = THIS_MODULE, }; diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c index effcd0ac98d8..15e3b850f513 100644 --- a/drivers/iio/trigger/iio-trig-sysfs.c +++ b/drivers/iio/trigger/iio-trig-sysfs.c @@ -23,7 +23,7 @@ struct iio_sysfs_trig { }; static LIST_HEAD(iio_sysfs_trig_list); -static DEFINE_MUTEX(iio_syfs_trig_list_mut); +static DEFINE_MUTEX(iio_sysfs_trig_list_mut); static int iio_sysfs_trigger_probe(int id); static ssize_t iio_sysfs_trig_add(struct device *dev, @@ -135,7 +135,7 @@ static int iio_sysfs_trigger_probe(int id) struct iio_sysfs_trig *t; int ret; bool foundit = false; - mutex_lock(&iio_syfs_trig_list_mut); + mutex_lock(&iio_sysfs_trig_list_mut); list_for_each_entry(t, &iio_sysfs_trig_list, l) if (id == t->id) { foundit = true; @@ -169,7 +169,7 @@ static int iio_sysfs_trigger_probe(int id) goto out2; list_add(&t->l, &iio_sysfs_trig_list); __module_get(THIS_MODULE); - mutex_unlock(&iio_syfs_trig_list_mut); + mutex_unlock(&iio_sysfs_trig_list_mut); return 0; out2: @@ -177,7 +177,7 @@ out2: free_t: kfree(t); out1: - mutex_unlock(&iio_syfs_trig_list_mut); + mutex_unlock(&iio_sysfs_trig_list_mut); return ret; } @@ -185,14 +185,14 @@ static int iio_sysfs_trigger_remove(int id) { bool foundit = false; struct iio_sysfs_trig *t; - mutex_lock(&iio_syfs_trig_list_mut); + mutex_lock(&iio_sysfs_trig_list_mut); list_for_each_entry(t, &iio_sysfs_trig_list, l) if (id == t->id) { foundit = true; break; } if (!foundit) { - mutex_unlock(&iio_syfs_trig_list_mut); + mutex_unlock(&iio_sysfs_trig_list_mut); return -EINVAL; } @@ -202,7 +202,7 @@ static int iio_sysfs_trigger_remove(int id) list_del(&t->l); kfree(t); module_put(THIS_MODULE); - mutex_unlock(&iio_syfs_trig_list_mut); + mutex_unlock(&iio_sysfs_trig_list_mut); return 0; } diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index e1c5300cacfc..24e625c0b531 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -52,6 +52,7 @@ struct titsc { u32 config_inp[4]; u32 bit_xp, bit_xn, bit_yp, bit_yn; u32 inp_xp, inp_xn, inp_yp, inp_yn; + u32 step_mask; }; static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) @@ -196,7 +197,8 @@ static void titsc_step_config(struct titsc *ts_dev) /* The steps1 … end and bit 0 for TS_Charge */ stepenable = (1 << (end_step + 2)) - 1; - am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable); + ts_dev->step_mask = stepenable; + am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask); } static void titsc_read_coordinates(struct titsc *ts_dev, @@ -260,6 +262,10 @@ static irqreturn_t titsc_irq(int irq, void *dev) unsigned int fsm; status = titsc_readl(ts_dev, REG_IRQSTATUS); + /* + * ADC and touchscreen share the IRQ line. + * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only + */ if (status & IRQENB_FIFO0THRES) { titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2); @@ -316,7 +322,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) if (irqclr) { titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); - am335x_tsc_se_update(ts_dev->mfd_tscadc); + am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask); return IRQ_HANDLED; } return IRQ_NONE; @@ -389,7 +395,7 @@ static int titsc_probe(struct platform_device *pdev) } err = request_irq(ts_dev->irq, titsc_irq, - 0, pdev->dev.driver->name, ts_dev); + IRQF_SHARED, pdev->dev.driver->name, ts_dev); if (err) { dev_err(&pdev->dev, "failed to allocate irq.\n"); goto err_free_mem; diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 4e2a81854f51..45560ffb038d 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -275,6 +275,12 @@ static int hid_time_probe(struct platform_device *pdev) return ret; } + ret = sensor_hub_device_open(hsdev); + if (ret) { + dev_err(&pdev->dev, "failed to open sensor hub device!\n"); + goto err_open; + } + time_state->rtc = devm_rtc_device_register(&pdev->dev, "hid-sensor-time", &hid_time_rtc_ops, THIS_MODULE); @@ -282,17 +288,24 @@ static int hid_time_probe(struct platform_device *pdev) if (IS_ERR_OR_NULL(time_state->rtc)) { ret = time_state->rtc ? PTR_ERR(time_state->rtc) : -ENODEV; time_state->rtc = NULL; - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); dev_err(&pdev->dev, "rtc device register failed!\n"); + goto err_rtc; } return ret; + +err_rtc: + sensor_hub_device_close(hsdev); +err_open: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); + return ret; } static int hid_time_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + sensor_hub_device_close(hsdev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); return 0; diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 3626dbc8eb0b..3b1501b7d894 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -136,6 +136,8 @@ source "drivers/staging/goldfish/Kconfig" source "drivers/staging/netlogic/Kconfig" +source "drivers/staging/mt29f_spinand/Kconfig" + source "drivers/staging/dwc2/Kconfig" source "drivers/staging/lustre/Kconfig" @@ -148,4 +150,6 @@ source "drivers/staging/dgnc/Kconfig" source "drivers/staging/dgap/Kconfig" +source "drivers/staging/ktap/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index d1b4b8003c2d..2270ed077bde 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -66,3 +66,5 @@ obj-$(CONFIG_USB_BTMTK) += btmtk_usb/ obj-$(CONFIG_XILLYBUS) += xillybus/ obj-$(CONFIG_DGNC) += dgnc/ obj-$(CONFIG_DGAP) += dgap/ +obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ +obj-$(CONFIG_KTAP) += ktap/ diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index c0c95be0f969..1e9ab6dfc90d 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -10,6 +10,7 @@ if ANDROID config ANDROID_BINDER_IPC bool "Android Binder IPC Driver" + depends on MMU default n ---help--- Binder is used in Android for both communication between processes, @@ -76,7 +77,7 @@ config SYNC bool "Synchronization framework" default n select ANON_INODES - help + ---help--- This option enables the framework for synchronization between multiple drivers. Sync implementations can take advantage of hardware synchronization built into devices like GPUs. @@ -85,7 +86,7 @@ config SW_SYNC bool "Software synchronization objects" default n depends on SYNC - help + ---help--- A sync object driver that uses a 32bit counter to coordinate syncrhronization. Useful when there is no hardware primitive backing the synchronization. @@ -94,7 +95,7 @@ config SW_SYNC_USER bool "Userspace API for SW_SYNC" default n depends on SW_SYNC - help + ---help--- Provides a user space API to the sw sync object. *WARNING* improper use of this can result in deadlocking kernel drivers from userspace. diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c index 6dc27dac679d..647694f43dcf 100644 --- a/drivers/staging/android/alarm-dev.c +++ b/drivers/staging/android/alarm-dev.c @@ -60,7 +60,12 @@ struct devalarm { static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT]; - +/** + * is_wakeup() - Checks to see if this alarm can wake the device + * @type: The type of alarm being checked + * + * Return: 1 if this is a wakeup alarm, otherwise 0 + */ static int is_wakeup(enum android_alarm_type type) { return (type == ANDROID_ALARM_RTC_WAKEUP || @@ -76,7 +81,6 @@ static void devalarm_start(struct devalarm *alrm, ktime_t exp) hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS); } - static int devalarm_try_to_cancel(struct devalarm *alrm) { if (is_wakeup(alrm->type)) diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 8e76ddca0999..db5325c88f1c 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -37,41 +37,59 @@ #define ASHMEM_NAME_PREFIX_LEN (sizeof(ASHMEM_NAME_PREFIX) - 1) #define ASHMEM_FULL_NAME_LEN (ASHMEM_NAME_LEN + ASHMEM_NAME_PREFIX_LEN) -/* - * ashmem_area - anonymous shared memory area - * Lifecycle: From our parent file's open() until its release() - * Locking: Protected by `ashmem_mutex' - * Big Note: Mappings do NOT pin this structure; it dies on close() +/** + * struct ashmem_area - The anonymous shared memory area + * @name: The optional name in /proc/pid/maps + * @unpinned_list: The list of all ashmem areas + * @file: The shmem-based backing file + * @size: The size of the mapping, in bytes + * @prot_masks: The allowed protection bits, as vm_flags + * + * The lifecycle of this structure is from our parent file's open() until + * its release(). It is also protected by 'ashmem_mutex' + * + * Warning: Mappings do NOT pin this structure; It dies on close() */ struct ashmem_area { - char name[ASHMEM_FULL_NAME_LEN]; /* optional name in /proc/pid/maps */ - struct list_head unpinned_list; /* list of all ashmem areas */ - struct file *file; /* the shmem-based backing file */ - size_t size; /* size of the mapping, in bytes */ - unsigned long prot_mask; /* allowed prot bits, as vm_flags */ + char name[ASHMEM_FULL_NAME_LEN]; + struct list_head unpinned_list; + struct file *file; + size_t size; + unsigned long prot_mask; }; -/* - * ashmem_range - represents an interval of unpinned (evictable) pages - * Lifecycle: From unpin to pin - * Locking: Protected by `ashmem_mutex' +/** + * struct ashmem_range - A range of unpinned/evictable pages + * @lru: The entry in the LRU list + * @unpinned: The entry in its area's unpinned list + * @asma: The associated anonymous shared memory area. + * @pgstart: The starting page (inclusive) + * @pgend: The ending page (inclusive) + * @purged: The purge status (ASHMEM_NOT or ASHMEM_WAS_PURGED) + * + * The lifecycle of this structure is from unpin to pin. + * It is protected by 'ashmem_mutex' */ struct ashmem_range { - struct list_head lru; /* entry in LRU list */ - struct list_head unpinned; /* entry in its area's unpinned list */ - struct ashmem_area *asma; /* associated area */ - size_t pgstart; /* starting page, inclusive */ - size_t pgend; /* ending page, inclusive */ - unsigned int purged; /* ASHMEM_NOT or ASHMEM_WAS_PURGED */ + struct list_head lru; + struct list_head unpinned; + struct ashmem_area *asma; + size_t pgstart; + size_t pgend; + unsigned int purged; }; /* LRU list of unpinned pages, protected by ashmem_mutex */ static LIST_HEAD(ashmem_lru_list); -/* Count of pages on our LRU list, protected by ashmem_mutex */ +/** + * long lru_count - The count of pages on our LRU list. + * + * This is protected by ashmem_mutex. + */ static unsigned long lru_count; -/* +/** * ashmem_mutex - protects the list of and each individual ashmem_area * * Lock Ordering: ashmex_mutex -> i_mutex -> i_alloc_sem @@ -105,28 +123,43 @@ static struct kmem_cache *ashmem_range_cachep __read_mostly; #define PROT_MASK (PROT_EXEC | PROT_READ | PROT_WRITE) +/** + * lru_add() - Adds a range of memory to the LRU list + * @range: The memory range being added. + * + * The range is first added to the end (tail) of the LRU list. + * After this, the size of the range is added to @lru_count + */ static inline void lru_add(struct ashmem_range *range) { list_add_tail(&range->lru, &ashmem_lru_list); lru_count += range_size(range); } +/** + * lru_del() - Removes a range of memory from the LRU list + * @range: The memory range being removed + * + * The range is first deleted from the LRU list. + * After this, the size of the range is removed from @lru_count + */ static inline void lru_del(struct ashmem_range *range) { list_del(&range->lru); lru_count -= range_size(range); } -/* - * range_alloc - allocate and initialize a new ashmem_range structure +/** + * range_alloc() - Allocates and initializes a new ashmem_range structure + * @asma: The associated ashmem_area + * @prev_range: The previous ashmem_range in the sorted asma->unpinned list + * @purged: Initial purge status (ASMEM_NOT_PURGED or ASHMEM_WAS_PURGED) + * @start: The starting page (inclusive) + * @end: The ending page (inclusive) * - * 'asma' - associated ashmem_area - * 'prev_range' - the previous ashmem_range in the sorted asma->unpinned list - * 'purged' - initial purge value (ASMEM_NOT_PURGED or ASHMEM_WAS_PURGED) - * 'start' - starting page, inclusive - * 'end' - ending page, inclusive + * This function is protected by ashmem_mutex. * - * Caller must hold ashmem_mutex. + * Return: 0 if successful, or -ENOMEM if there is an error */ static int range_alloc(struct ashmem_area *asma, struct ashmem_range *prev_range, unsigned int purged, @@ -151,6 +184,10 @@ static int range_alloc(struct ashmem_area *asma, return 0; } +/** + * range_del() - Deletes and dealloctes an ashmem_range structure + * @range: The associated ashmem_range that has previously been allocated + */ static void range_del(struct ashmem_range *range) { list_del(&range->unpinned); @@ -159,10 +196,17 @@ static void range_del(struct ashmem_range *range) kmem_cache_free(ashmem_range_cachep, range); } -/* - * range_shrink - shrinks a range +/** + * range_shrink() - Shrinks an ashmem_range + * @range: The associated ashmem_range being shrunk + * @start: The starting byte of the new range + * @end: The ending byte of the new range * - * Caller must hold ashmem_mutex. + * This does not modify the data inside the existing range in any way - It + * simply shrinks the boundaries of the range. + * + * Theoretically, with a little tweaking, this could eventually be changed + * to range_resize, and expand the lru_count if the new range is larger. */ static inline void range_shrink(struct ashmem_range *range, size_t start, size_t end) @@ -176,6 +220,16 @@ static inline void range_shrink(struct ashmem_range *range, lru_count -= pre - range_size(range); } +/** + * ashmem_open() - Opens an Anonymous Shared Memory structure + * @inode: The backing file's index node(?) + * @file: The backing file + * + * Please note that the ashmem_area is not returned by this function - It is + * instead written to "file->private_data". + * + * Return: 0 if successful, or another code if unsuccessful. + */ static int ashmem_open(struct inode *inode, struct file *file) { struct ashmem_area *asma; @@ -197,6 +251,14 @@ static int ashmem_open(struct inode *inode, struct file *file) return 0; } +/** + * ashmem_release() - Releases an Anonymous Shared Memory structure + * @ignored: The backing file's Index Node(?) - It is ignored here. + * @file: The backing file + * + * Return: 0 if successful. If it is anything else, go have a coffee and + * try again. + */ static int ashmem_release(struct inode *ignored, struct file *file) { struct ashmem_area *asma = file->private_data; @@ -214,6 +276,15 @@ static int ashmem_release(struct inode *ignored, struct file *file) return 0; } +/** + * ashmem_read() - Reads a set of bytes from an Ashmem-enabled file + * @file: The associated backing file. + * @buf: The buffer of data being written to + * @len: The number of bytes being read + * @pos: The position of the first byte to read. + * + * Return: 0 if successful, or another return code if not. + */ static ssize_t ashmem_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 98ac020bf912..eaec1dab7fe4 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -1700,7 +1700,8 @@ err_no_context_mgr_node: thread->return_error = return_error; } -int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, +static int binder_thread_write(struct binder_proc *proc, + struct binder_thread *thread, void __user *buffer, size_t size, size_t *consumed) { uint32_t cmd; @@ -1773,7 +1774,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { void __user *node_ptr; - void *cookie; + void __user *cookie; struct binder_node *node; if (get_user(node_ptr, (void * __user *)ptr)) @@ -2055,8 +2056,8 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, return 0; } -void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, - uint32_t cmd) +static void binder_stat_br(struct binder_proc *proc, + struct binder_thread *thread, uint32_t cmd) { trace_binder_return(cmd); if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { diff --git a/drivers/staging/android/timed_output.h b/drivers/staging/android/timed_output.h index ec907ab2ff54..905c7cc9588e 100644 --- a/drivers/staging/android/timed_output.h +++ b/drivers/staging/android/timed_output.h @@ -31,7 +31,7 @@ struct timed_output_dev { int state; }; -extern int timed_output_dev_register(struct timed_output_dev *dev); -extern void timed_output_dev_unregister(struct timed_output_dev *dev); +int timed_output_dev_register(struct timed_output_dev *dev); +void timed_output_dev_unregister(struct timed_output_dev *dev); #endif diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 4e470d4bb4e8..a567894753aa 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -142,7 +142,8 @@ static void bcm_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); - struct bcm_interface_adapter *psIntfAdapter = Adapter->pvInterfaceAdapter; + struct bcm_interface_adapter *psIntfAdapter = + Adapter->pvInterfaceAdapter; struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface); strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c index afca010f9db5..d9fa2bb03e11 100644 --- a/drivers/staging/bcm/InterfaceMisc.c +++ b/drivers/staging/bcm/InterfaceMisc.c @@ -104,7 +104,7 @@ int BcmRDM(void *arg, void *buff, int len) { - return InterfaceRDM((struct bcm_interface_adapter*)arg, addr, buff, len); + return InterfaceRDM((struct bcm_interface_adapter *)arg, addr, buff, len); } int BcmWRM(void *arg, diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c index af5d22faa7f0..56c5bee6514e 100644 --- a/drivers/staging/bcm/PHSModule.c +++ b/drivers/staging/bcm/PHSModule.c @@ -596,7 +596,7 @@ ULONG PhsDeleteSFRules(IN void *pvContext, IN B_UINT16 uiVcid) * 0 if successful, * >0 Error. */ -ULONG PhsCompress(IN void *pvContext, +static ULONG PhsCompress(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT16 uiClsId, IN void *pvInputBuffer, @@ -677,7 +677,7 @@ ULONG PhsCompress(IN void *pvContext, * 0 if successful, * >0 Error. */ -ULONG PhsDeCompress(IN void *pvContext, +static ULONG PhsDeCompress(IN void *pvContext, IN B_UINT16 uiVcid, IN void *pvInputBuffer, OUT void *pvOutputBuffer, @@ -829,7 +829,7 @@ UINT GetServiceFlowEntry(IN struct bcm_phs_table *psServiceFlowTable, return PHS_INVALID_TABLE_INDEX; } -UINT GetClassifierEntry(IN struct bcm_phs_classifier_table *pstClassifierTable, +static UINT GetClassifierEntry(IN struct bcm_phs_classifier_table *pstClassifierTable, IN B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext, OUT struct bcm_phs_classifier_entry **ppstClassifierEntry) { @@ -880,7 +880,7 @@ static UINT GetPhsRuleEntry(IN struct bcm_phs_classifier_table *pstClassifierTab return PHS_INVALID_TABLE_INDEX; } -UINT CreateSFToClassifierRuleMapping(IN B_UINT16 uiVcid, IN B_UINT16 uiClsId, +static UINT CreateSFToClassifierRuleMapping(IN B_UINT16 uiVcid, IN B_UINT16 uiClsId, IN struct bcm_phs_table *psServiceFlowTable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI) @@ -913,7 +913,7 @@ UINT CreateSFToClassifierRuleMapping(IN B_UINT16 uiVcid, IN B_UINT16 uiClsId, return uiStatus; } -UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid, +static UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid, IN B_UINT16 uiClsId, IN struct bcm_phs_entry *pstServiceFlowEntry, struct bcm_phs_rule *psPhsRule, @@ -1239,7 +1239,7 @@ void DumpPhsRules(struct bcm_phs_extension *pDeviceExtension) * header. * 0 -If PHS rule is NULL.If PHSI is 0 indicateing packet as uncompressed. */ -int phs_decompress(unsigned char *in_buf, +static int phs_decompress(unsigned char *in_buf, unsigned char *out_buf, struct bcm_phs_rule *decomp_phs_rules, UINT *header_size) diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c index 91a5715964b9..1f5b62b4b5a1 100644 --- a/drivers/staging/bcm/nvm.c +++ b/drivers/staging/bcm/nvm.c @@ -103,7 +103,7 @@ static UCHAR ReadEEPROMStatusRegister(struct bcm_mini_adapter *Adapter) } if (!(dwRetries%RETRIES_PER_DELAY)) udelay(1000); - uiStatus = 0 ; + uiStatus = 0; } return uiData; } /* ReadEEPROMStatusRegister */ @@ -1095,7 +1095,7 @@ static int BeceemFlashBulkWrite(struct bcm_mini_adapter *Adapter, goto BeceemFlashBulkWrite_EXIT; } uiTemp = uiTemp - 1; - index = index + 1 ; + index = index + 1; } } Adapter->SelectedChip = RESET_CHIP_SELECT; @@ -1276,7 +1276,7 @@ static int BeceemFlashBulkWriteStatus(struct bcm_mini_adapter *Adapter, goto BeceemFlashBulkWriteStatus_EXIT; } uiTemp = uiTemp - 1; - index = index + 1 ; + index = index + 1; } } @@ -2831,7 +2831,7 @@ int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x SectEndOffset = INVALID_OFFSET; } - return SectEndOffset ; + return SectEndOffset; } /* @@ -3358,7 +3358,7 @@ int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_secti /* struct bcm_dsd_header sDSD = {0}; * struct bcm_iso_header sISO = {0}; */ - int HighestPriDSD = 0 ; + int HighestPriDSD = 0; int HighestPriISO = 0; Status = IsSectionWritable(Adapter, eFlash2xSectVal); @@ -4450,7 +4450,7 @@ int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter, BcmDoChipSelect(Adapter, uiOffset); uiPartOffset = (uiOffset & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter); - for (i = 0 ; i < uiNumBytes; i += Adapter->ulFlashWriteSize) { + for (i = 0; i < uiNumBytes; i += Adapter->ulFlashWriteSize) { if (Adapter->ulFlashWriteSize == BYTE_WRITE_SUPPORT) Status = flashByteWrite(Adapter, uiPartOffset, pcBuff); else diff --git a/drivers/staging/btmtk_usb/btmtk_usb.c b/drivers/staging/btmtk_usb/btmtk_usb.c index 0e783e8d71ca..7a9bf3b57810 100644 --- a/drivers/staging/btmtk_usb/btmtk_usb.c +++ b/drivers/staging/btmtk_usb/btmtk_usb.c @@ -16,7 +16,8 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * or on the worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * or on the worldwide web at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * */ @@ -72,8 +73,9 @@ static int btmtk_usb_reset(struct usb_device *udev) BT_DBG("%s\n", __func__); - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01, DEVICE_VENDOR_REQUEST_OUT, - 0x01, 0x00, NULL, 0x00, CONTROL_TIMEOUT_JIFFIES); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01, + DEVICE_VENDOR_REQUEST_OUT, 0x01, 0x00, + NULL, 0x00, CONTROL_TIMEOUT_JIFFIES); if (ret < 0) { BT_ERR("%s error(%d)\n", __func__, ret); @@ -91,20 +93,22 @@ static int btmtk_usb_io_read32(struct btmtk_usb_data *data, u32 reg, u32 *val) u8 request = data->r_request; struct usb_device *udev = data->udev; int ret; + __le32 val_le; - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), request, DEVICE_VENDOR_REQUEST_IN, - 0x0, reg, data->io_buf, 4, - CONTROL_TIMEOUT_JIFFIES); + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), request, + DEVICE_VENDOR_REQUEST_IN, 0x0, reg, data->io_buf, + 4, CONTROL_TIMEOUT_JIFFIES); if (ret < 0) { *val = 0xffffffff; - BT_ERR("%s error(%d), reg=%x, value=%x\n", __func__, ret, reg, *val); + BT_ERR("%s error(%d), reg=%x, value=%x\n", + __func__, ret, reg, *val); return ret; } - memmove(val, data->io_buf, 4); + memmove(&val_le, data->io_buf, 4); - *val = le32_to_cpu(*val); + *val = le32_to_cpu(val_le); if (ret > 0) ret = 0; @@ -122,12 +126,13 @@ static int btmtk_usb_io_write32(struct btmtk_usb_data *data, u32 reg, u32 val) index = (u16)reg; value = val & 0x0000ffff; - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, DEVICE_VENDOR_REQUEST_OUT, - value, index, NULL, 0, - CONTROL_TIMEOUT_JIFFIES); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, + DEVICE_VENDOR_REQUEST_OUT, value, index, + NULL, 0, CONTROL_TIMEOUT_JIFFIES); if (ret < 0) { - BT_ERR("%s error(%d), reg=%x, value=%x\n", __func__, ret, reg, val); + BT_ERR("%s error(%d), reg=%x, value=%x\n", + __func__, ret, reg, val); return ret; } @@ -139,7 +144,8 @@ static int btmtk_usb_io_write32(struct btmtk_usb_data *data, u32 reg, u32 val) value, index, NULL, 0, CONTROL_TIMEOUT_JIFFIES); if (ret < 0) { - BT_ERR("%s error(%d), reg=%x, value=%x\n", __func__, ret, reg, val); + BT_ERR("%s error(%d), reg=%x, value=%x\n", + __func__, ret, reg, val); return ret; } @@ -186,13 +192,15 @@ static void btmtk_usb_cap_init(struct btmtk_usb_data *data) ret = request_firmware(&firmware, MT7650_FIRMWARE, &udev->dev); if (ret < 0) { if (ret == -ENOENT) { - BT_ERR("Firmware file \"%s\" not found \n", MT7650_FIRMWARE); + BT_ERR("Firmware file \"%s\" not found\n", + MT7650_FIRMWARE); } else { - BT_ERR("Firmware file \"%s\" request failed (err=%d) \n", + BT_ERR("Firmware file \"%s\" request failed (err=%d)\n", MT7650_FIRMWARE, ret); } } else { - BT_DBG("Firmware file \"%s\" Found \n", MT7650_FIRMWARE); + BT_DBG("Firmware file \"%s\" Found\n", + MT7650_FIRMWARE); /* load firmware here */ data->firmware = firmware; btmtk_usb_load_fw(data); @@ -205,7 +213,8 @@ static void btmtk_usb_cap_init(struct btmtk_usb_data *data) ret = request_firmware(&firmware, MT7662_FIRMWARE, &udev->dev); if (ret < 0) { if (ret == -ENOENT) { - BT_ERR("Firmware file \"%s\" not found\n", MT7662_FIRMWARE); + BT_ERR("Firmware file \"%s\" not found\n", + MT7662_FIRMWARE); } else { BT_ERR("Firmware file \"%s\" request failed (err=%d)\n", MT7662_FIRMWARE, ret); @@ -241,9 +250,8 @@ static u16 checksume16(u8 *pData, int len) if (len) sum += *((u8 *)pData); - while (sum >> 16) { + while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16); - } return ~sum; } @@ -258,13 +266,12 @@ static int btmtk_usb_chk_crc(struct btmtk_usb_data *data, u32 checksum_len) memmove(data->io_buf, &data->rom_patch_offset, 4); memmove(&data->io_buf[4], &checksum_len, 4); - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x1, DEVICE_VENDOR_REQUEST_IN, - 0x20, 0x00, data->io_buf, 8, - CONTROL_TIMEOUT_JIFFIES); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x1, + DEVICE_VENDOR_REQUEST_IN, 0x20, 0x00, data->io_buf, + 8, CONTROL_TIMEOUT_JIFFIES); - if (ret < 0) { + if (ret < 0) BT_ERR("%s error(%d)\n", __func__, ret); - } return ret; } @@ -274,6 +281,7 @@ static u16 btmtk_usb_get_crc(struct btmtk_usb_data *data) int ret = 0; struct usb_device *udev = data->udev; u16 crc, count = 0; + __le16 crc_le; BT_DBG("%s\n", __func__); @@ -288,9 +296,9 @@ static u16 btmtk_usb_get_crc(struct btmtk_usb_data *data) BT_ERR("%s error(%d)\n", __func__, ret); } - memmove(&crc, data->io_buf, 2); + memmove(&crc_le, data->io_buf, 2); - crc = le16_to_cpu(crc); + crc = le16_to_cpu(crc_le); if (crc != 0xFFFF) break; @@ -318,8 +326,8 @@ static int btmtk_usb_reset_wmt(struct btmtk_usb_data *data) BT_DBG("%s\n", __func__); ret = usb_control_msg(data->udev, usb_sndctrlpipe(data->udev, 0), 0x01, - DEVICE_CLASS_REQUEST_OUT, 0x12, 0x00, data->io_buf, - 8, CONTROL_TIMEOUT_JIFFIES); + DEVICE_CLASS_REQUEST_OUT, 0x12, 0x00, + data->io_buf, 8, CONTROL_TIMEOUT_JIFFIES); if (ret) BT_ERR("%s:(%d)\n", __func__, ret); @@ -350,7 +358,8 @@ static int btmtk_usb_load_rom_patch(struct btmtk_usb_data *data) unsigned char phase; void *buf; char *pos; - unsigned int pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); + unsigned int pipe; + pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); if (!data->firmware) { BT_ERR("%s:please assign a rom patch\n", __func__); @@ -391,7 +400,8 @@ load_patch_protect: goto error0; } - buf = usb_alloc_coherent(data->udev, UPLOAD_PATCH_UNIT, GFP_ATOMIC, &data_dma); + buf = usb_alloc_coherent(data->udev, UPLOAD_PATCH_UNIT, + GFP_ATOMIC, &data_dma); if (!buf) { ret = -ENOMEM; @@ -409,78 +419,82 @@ load_patch_protect: /* loading rom patch */ while (1) { s32 sent_len_max = UPLOAD_PATCH_UNIT - PATCH_HEADER_SIZE; - sent_len = (patch_len - cur_len) >= sent_len_max ? sent_len_max : (patch_len - cur_len); + sent_len = min_t(s32, (patch_len - cur_len), sent_len_max); BT_DBG("patch_len = %d\n", patch_len); BT_DBG("cur_len = %d\n", cur_len); BT_DBG("sent_len = %d\n", sent_len); - if (sent_len > 0) { - if (first_block == 1) { - if (sent_len < sent_len_max) - phase = PATCH_PHASE3; - else - phase = PATCH_PHASE1; - first_block = 0; - } else if (sent_len == sent_len_max) { - phase = PATCH_PHASE2; - } else { + if (sent_len <= 0) + break; + + if (first_block == 1) { + if (sent_len < sent_len_max) phase = PATCH_PHASE3; - } + else + phase = PATCH_PHASE1; + first_block = 0; + } else if (sent_len == sent_len_max) { + phase = PATCH_PHASE2; + } else { + phase = PATCH_PHASE3; + } - /* prepare HCI header */ - pos[0] = 0x6F; - pos[1] = 0xFC; - pos[2] = (sent_len + 5) & 0xFF; - pos[3] = ((sent_len + 5) >> 8) & 0xFF; + /* prepare HCI header */ + pos[0] = 0x6F; + pos[1] = 0xFC; + pos[2] = (sent_len + 5) & 0xFF; + pos[3] = ((sent_len + 5) >> 8) & 0xFF; - /* prepare WMT header */ - pos[4] = 0x01; - pos[5] = 0x01; - pos[6] = (sent_len + 1) & 0xFF; - pos[7] = ((sent_len + 1) >> 8) & 0xFF; + /* prepare WMT header */ + pos[4] = 0x01; + pos[5] = 0x01; + pos[6] = (sent_len + 1) & 0xFF; + pos[7] = ((sent_len + 1) >> 8) & 0xFF; - pos[8] = phase; + pos[8] = phase; - memcpy(&pos[9], data->firmware->data + PATCH_INFO_SIZE + cur_len, sent_len); + memcpy(&pos[9], + data->firmware->data + PATCH_INFO_SIZE + cur_len, + sent_len); - BT_DBG("sent_len + PATCH_HEADER_SIZE = %d, phase = %d\n", - sent_len + PATCH_HEADER_SIZE, phase); + BT_DBG("sent_len + PATCH_HEADER_SIZE = %d, phase = %d\n", + sent_len + PATCH_HEADER_SIZE, phase); - usb_fill_bulk_urb(urb, - data->udev, - pipe, - buf, - sent_len + PATCH_HEADER_SIZE, - load_rom_patch_complete, - &sent_to_mcu_done); + usb_fill_bulk_urb(urb, + data->udev, + pipe, + buf, + sent_len + PATCH_HEADER_SIZE, + load_rom_patch_complete, + &sent_to_mcu_done); - urb->transfer_dma = data_dma; - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + urb->transfer_dma = data_dma; + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - ret = usb_submit_urb(urb, GFP_ATOMIC); + ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - goto error2; + if (ret) + goto error2; - if (!wait_for_completion_timeout(&sent_to_mcu_done, msecs_to_jiffies(1000))) { - usb_kill_urb(urb); - BT_ERR("upload rom_patch timeout\n"); - goto error2; - } + if (!wait_for_completion_timeout(&sent_to_mcu_done, + msecs_to_jiffies(1000))) { + usb_kill_urb(urb); + BT_ERR("upload rom_patch timeout\n"); + goto error2; + } - BT_DBG("."); + BT_DBG("."); - mdelay(200); + mdelay(200); - cur_len += sent_len; + cur_len += sent_len; - } else { - break; - } } - total_checksum = checksume16((u8 *)data->firmware->data + PATCH_INFO_SIZE, patch_len); + total_checksum = checksume16( + (u8 *)data->firmware->data + PATCH_INFO_SIZE, + patch_len); BT_DBG("Send checksum req..\n"); @@ -520,8 +534,8 @@ static int load_fw_iv(struct btmtk_usb_data *data) memmove(buf, data->firmware->data + 32, 64); ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01, - DEVICE_VENDOR_REQUEST_OUT, 0x12, 0x0, buf, 64, - CONTROL_TIMEOUT_JIFFIES); + DEVICE_VENDOR_REQUEST_OUT, 0x12, 0x0, buf, 64, + CONTROL_TIMEOUT_JIFFIES); if (ret < 0) { BT_ERR("%s error(%d) step4\n", __func__, ret); @@ -552,6 +566,7 @@ static int btmtk_usb_load_fw(struct btmtk_usb_data *data) void *buf; u32 cur_len = 0; u32 packet_header = 0; + __le32 packet_header_le; u32 value; u32 ilm_len = 0, dlm_len = 0; u16 fw_ver, build_ver; @@ -559,7 +574,8 @@ static int btmtk_usb_load_fw(struct btmtk_usb_data *data) dma_addr_t data_dma; int ret = 0, sent_len; struct completion sent_to_mcu_done; - unsigned int pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); + unsigned int pipe; + pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); if (!data->firmware) { BT_ERR("%s:please assign a fw\n", __func__); @@ -598,9 +614,11 @@ loadfw_protect: | (*(data->firmware->data + 5) << 8) | (*(data->firmware->data + 4)); - fw_ver = (*(data->firmware->data + 11) << 8) | (*(data->firmware->data + 10)); + fw_ver = (*(data->firmware->data + 11) << 8) | + (*(data->firmware->data + 10)); - build_ver = (*(data->firmware->data + 9) << 8) | (*(data->firmware->data + 8)); + build_ver = (*(data->firmware->data + 9) << 8) | + (*(data->firmware->data + 8)); BT_DBG("fw version:%d.%d.%02d ", (fw_ver & 0xf000) >> 8, @@ -657,22 +675,22 @@ loadfw_protect: /* Loading ILM */ while (1) { - sent_len = (ilm_len - cur_len) >= 14336 ? 14336 : (ilm_len - cur_len); + sent_len = min_t(s32, (ilm_len - cur_len), 14336); if (sent_len > 0) { packet_header &= ~(0xffffffff); packet_header |= (sent_len << 16); - packet_header = cpu_to_le32(packet_header); + packet_header_le = cpu_to_le32(packet_header); - memmove(buf, &packet_header, 4); - memmove(buf + 4, data->firmware->data + 32 + cur_len, sent_len); + memmove(buf, &packet_header_le, 4); + memmove(buf + 4, data->firmware->data + 32 + cur_len, + sent_len); /* U2M_PDMA descriptor */ btmtk_usb_io_write32(data, 0x230, cur_len); - while ((sent_len % 4) != 0) { + while ((sent_len % 4) != 0) sent_len++; - } /* U2M_PDMA length */ btmtk_usb_io_write32(data, 0x234, sent_len << 16); @@ -693,7 +711,8 @@ loadfw_protect: if (ret) goto error3; - if (!wait_for_completion_timeout(&sent_to_mcu_done, msecs_to_jiffies(1000))) { + if (!wait_for_completion_timeout(&sent_to_mcu_done, + msecs_to_jiffies(1000))) { usb_kill_urb(urb); BT_ERR("upload ilm fw timeout\n"); goto error3; @@ -714,58 +733,60 @@ loadfw_protect: /* Loading DLM */ while (1) { - sent_len = (dlm_len - cur_len) >= 14336 ? 14336 : (dlm_len - cur_len); + sent_len = min_t(s32, (dlm_len - cur_len), 14336); - if (sent_len > 0) { - packet_header &= ~(0xffffffff); - packet_header |= (sent_len << 16); - packet_header = cpu_to_le32(packet_header); + if (sent_len <= 0) + break; - memmove(buf, &packet_header, 4); - memmove(buf + 4, data->firmware->data + 32 + ilm_len + cur_len, sent_len); + packet_header &= ~(0xffffffff); + packet_header |= (sent_len << 16); + packet_header_le = cpu_to_le32(packet_header); - /* U2M_PDMA descriptor */ - btmtk_usb_io_write32(data, 0x230, 0x80000 + cur_len); + memmove(buf, &packet_header_le, 4); + memmove(buf + 4, + data->firmware->data + 32 + ilm_len + cur_len, + sent_len); - while ((sent_len % 4) != 0) { - BT_DBG("sent_len is not divided by 4\n"); - sent_len++; - } + /* U2M_PDMA descriptor */ + btmtk_usb_io_write32(data, 0x230, 0x80000 + cur_len); - /* U2M_PDMA length */ - btmtk_usb_io_write32(data, 0x234, sent_len << 16); + while ((sent_len % 4) != 0) { + BT_DBG("sent_len is not divided by 4\n"); + sent_len++; + } - usb_fill_bulk_urb(urb, - udev, - pipe, - buf, - sent_len + 4, - load_fw_complete, - &sent_to_mcu_done); + /* U2M_PDMA length */ + btmtk_usb_io_write32(data, 0x234, sent_len << 16); - urb->transfer_dma = data_dma; - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usb_fill_bulk_urb(urb, + udev, + pipe, + buf, + sent_len + 4, + load_fw_complete, + &sent_to_mcu_done); - ret = usb_submit_urb(urb, GFP_ATOMIC); + urb->transfer_dma = data_dma; + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (ret) - goto error3; + ret = usb_submit_urb(urb, GFP_ATOMIC); - if (!wait_for_completion_timeout(&sent_to_mcu_done, msecs_to_jiffies(1000))) { - usb_kill_urb(urb); - BT_ERR("upload dlm fw timeout\n"); - goto error3; - } + if (ret) + goto error3; - BT_DBG("."); + if (!wait_for_completion_timeout(&sent_to_mcu_done, + msecs_to_jiffies(1000))) { + usb_kill_urb(urb); + BT_ERR("upload dlm fw timeout\n"); + goto error3; + } - mdelay(500); + BT_DBG("."); - cur_len += sent_len; + mdelay(500); + + cur_len += sent_len; - } else { - break; - } } /* upload 64bytes interrupt vector */ @@ -921,9 +942,8 @@ static void btmtk_usb_bulk_in_complete(struct urb *urb) BT_DBG("%s:%s urb %p status %d count %d", __func__, hdev->name, urb, urb->status, urb->actual_length); - if (!test_bit(HCI_RUNNING, &hdev->flags)) { + if (!test_bit(HCI_RUNNING, &hdev->flags)) return; - } if (urb->status == 0) { hdev->stat.byte_rx += urb->actual_length; @@ -978,8 +998,8 @@ static int btmtk_usb_submit_bulk_in_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress); - usb_fill_bulk_urb(urb, data->udev, pipe, - buf, size, btmtk_usb_bulk_in_complete, hdev); + usb_fill_bulk_urb(urb, data->udev, pipe, buf, size, + btmtk_usb_bulk_in_complete, hdev); urb->transfer_flags |= URB_FREE_BUFFER; @@ -1015,7 +1035,8 @@ static void btmtk_usb_isoc_in_complete(struct urb *urb) if (urb->status == 0) { for (i = 0; i < urb->number_of_packets; i++) { unsigned int offset = urb->iso_frame_desc[i].offset; - unsigned int length = urb->iso_frame_desc[i].actual_length; + unsigned int length; + length = urb->iso_frame_desc[i].actual_length; if (urb->iso_frame_desc[i].status) continue; @@ -1096,8 +1117,9 @@ static int btmtk_usb_submit_isoc_in_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); - usb_fill_int_urb(urb, data->udev, pipe, buf, size, btmtk_usb_isoc_in_complete, - hdev, data->isoc_rx_ep->bInterval); + usb_fill_int_urb(urb, data->udev, pipe, buf, size, + btmtk_usb_isoc_in_complete, hdev, + data->isoc_rx_ep->bInterval); urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; @@ -1306,7 +1328,8 @@ static int btmtk_usb_send_frame(struct sk_buff *skb) } usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, - skb->data, skb->len, btmtk_usb_tx_complete, skb); + skb->data, skb->len, + btmtk_usb_tx_complete, skb); hdev->stat.cmd_tx++; break; @@ -1322,8 +1345,8 @@ static int btmtk_usb_send_frame(struct sk_buff *skb) pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); - usb_fill_bulk_urb(urb, data->udev, pipe, - skb->data, skb->len, btmtk_usb_tx_complete, skb); + usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, + skb->len, btmtk_usb_tx_complete, skb); hdev->stat.acl_tx++; BT_DBG("HCI_ACLDATA_PKT:\n"); @@ -1442,7 +1465,8 @@ static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting) static void btmtk_usb_work(struct work_struct *work) { - struct btmtk_usb_data *data = container_of(work, struct btmtk_usb_data, work); + struct btmtk_usb_data *data = container_of(work, struct btmtk_usb_data, + work); struct hci_dev *hdev = data->hdev; int new_alts; int err; @@ -1451,7 +1475,8 @@ static void btmtk_usb_work(struct work_struct *work) if (hdev->conn_hash.sco_num > 0) { if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) { - err = usb_autopm_get_interface(data->isoc ? data->isoc : data->intf); + err = usb_autopm_get_interface(data->isoc ? + data->isoc : data->intf); if (err < 0) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); @@ -1489,13 +1514,15 @@ static void btmtk_usb_work(struct work_struct *work) __set_isoc_interface(hdev, 0); if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags)) - usb_autopm_put_interface(data->isoc ? data->isoc : data->intf); + usb_autopm_put_interface(data->isoc ? + data->isoc : data->intf); } } static void btmtk_usb_waker(struct work_struct *work) { - struct btmtk_usb_data *data = container_of(work, struct btmtk_usb_data, waker); + struct btmtk_usb_data *data = container_of(work, struct btmtk_usb_data, + waker); int err; err = usb_autopm_get_interface(data->intf); diff --git a/drivers/staging/ced1401/ced_ioc.c b/drivers/staging/ced1401/ced_ioc.c index 2dbaf39e2fc2..62efd74b8c04 100644 --- a/drivers/staging/ced1401/ced_ioc.c +++ b/drivers/staging/ced1401/ced_ioc.c @@ -692,10 +692,7 @@ static int SetArea(DEVICE_EXTENSION *pdx, int nArea, char __user *puBuf, __func__, puBuf, dwLength, bCircular); /* To pin down user pages we must first acquire the mapping semaphore. */ - down_read(¤t->mm->mmap_sem); /* get memory map semaphore */ - nPages = get_user_pages(current, current->mm, ulStart, len, 1, 0, - pPages, NULL); - up_read(¤t->mm->mmap_sem); /* release the semaphore */ + nPages = get_user_pages_fast(ulStart, len, 1, pPages); dev_dbg(&pdx->interface->dev, "%s nPages = %d", __func__, nPages); if (nPages > 0) { /* if we succeeded */ diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index f73287eab373..bfa27e7fc016 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -485,6 +485,7 @@ config COMEDI_NI_ATMIO tristate "NI AT-MIO E series ISA-PNP card support" select COMEDI_8255 select COMEDI_NI_TIO + select COMEDI_FC ---help--- Enable support for National Instruments AT-MIO E series cards National Instruments AT-MIO-16E-1 (ni_atmio), @@ -990,8 +991,6 @@ config COMEDI_ME_DAQ config COMEDI_NI_6527 tristate "NI 6527 support" - depends on HAS_DMA - select COMEDI_MITE ---help--- Enable support for the National Instruments 6527 PCI card diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index 94b2385fb0af..4e26bd7fc84f 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -344,7 +344,7 @@ unsigned int comedi_buf_read_free(struct comedi_async *async, } EXPORT_SYMBOL_GPL(comedi_buf_read_free); -int comedi_buf_put(struct comedi_async *async, short x) +int comedi_buf_put(struct comedi_async *async, unsigned short x) { unsigned int n = __comedi_buf_write_alloc(async, sizeof(short), 1); @@ -352,20 +352,20 @@ int comedi_buf_put(struct comedi_async *async, short x) async->events |= COMEDI_CB_ERROR; return 0; } - *(short *)(async->prealloc_buf + async->buf_write_ptr) = x; + *(unsigned short *)(async->prealloc_buf + async->buf_write_ptr) = x; comedi_buf_write_free(async, sizeof(short)); return 1; } EXPORT_SYMBOL_GPL(comedi_buf_put); -int comedi_buf_get(struct comedi_async *async, short *x) +int comedi_buf_get(struct comedi_async *async, unsigned short *x) { unsigned int n = comedi_buf_read_n_available(async); if (n < sizeof(short)) return 0; comedi_buf_read_alloc(async, sizeof(short)); - *x = *(short *)(async->prealloc_buf + async->buf_read_ptr); + *x = *(unsigned short *)(async->prealloc_buf + async->buf_read_ptr); comedi_buf_read_free(async, sizeof(short)); return 1; } diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 1636c7ca57e2..721df313f8df 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -543,7 +543,7 @@ void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size) { s->private = kzalloc(size, GFP_KERNEL); if (s->private) - comedi_set_subdevice_runflags(s, ~0, SRF_FREE_SPRIV); + s->runflags |= SRF_FREE_SPRIV; return s->private; } EXPORT_SYMBOL_GPL(comedi_alloc_spriv); @@ -806,7 +806,6 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, } else { us->range_type = 0; /* XXX */ } - us->flags = s->flags; if (s->busy) us->subd_flags |= SDF_BUSY; @@ -818,8 +817,6 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, us->subd_flags |= SDF_LOCK_OWNER; if (!s->maxdata && s->maxdata_list) us->subd_flags |= SDF_MAXDATA; - if (s->flaglist) - us->subd_flags |= SDF_FLAGS; if (s->range_table_list) us->subd_flags |= SDF_RANGETYPE; if (s->do_cmd) @@ -829,8 +826,6 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, us->insn_bits_support = COMEDI_SUPPORTED; else us->insn_bits_support = COMEDI_UNSUPPORTED; - - us->settling_time_0 = s->settling_time_0; } ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp)); @@ -875,13 +870,8 @@ static int do_chaninfo_ioctl(struct comedi_device *dev, return -EFAULT; } - if (it.flaglist) { - if (!s->flaglist) - return -EINVAL; - if (copy_to_user(it.flaglist, s->flaglist, - s->n_chan * sizeof(unsigned int))) - return -EFAULT; - } + if (it.flaglist) + return -EINVAL; /* flaglist not supported */ if (it.rangelist) { int i; @@ -1485,7 +1475,8 @@ static int do_cmd_ioctl(struct comedi_device *dev, if (async->cmd.flags & TRIG_WAKE_EOS) async->cb_mask |= COMEDI_CB_EOS; - comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); + comedi_set_subdevice_runflags(s, SRF_USER | SRF_ERROR | SRF_RUNNING, + SRF_USER | SRF_RUNNING); /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with * comedi_read() or comedi_write() */ diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index 2e19f659cd22..143be8076a2e 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -57,11 +57,6 @@ struct comedi_subdevice { unsigned int maxdata; /* if maxdata==0, use list */ const unsigned int *maxdata_list; /* list is channel specific */ - unsigned int flags; - const unsigned int *flaglist; - - unsigned int settling_time_0; - const struct comedi_lrange *range_table; const struct comedi_lrange *const *range_table_list; @@ -307,7 +302,26 @@ static inline bool comedi_range_is_unipolar(struct comedi_subdevice *s, return s->range_table->range[range].min >= 0; } -/* some silly little inline functions */ +static inline bool comedi_chan_range_is_bipolar(struct comedi_subdevice *s, + unsigned int chan, + unsigned int range) +{ + return s->range_table_list[chan]->range[range].min < 0; +} + +static inline bool comedi_chan_range_is_unipolar(struct comedi_subdevice *s, + unsigned int chan, + unsigned int range) +{ + return s->range_table_list[chan]->range[range].min >= 0; +} + +/* munge between offset binary and two's complement values */ +static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s, + unsigned int val) +{ + return val ^ s->maxdata ^ (s->maxdata >> 1); +} static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd) { @@ -332,8 +346,8 @@ unsigned int comedi_buf_read_n_available(struct comedi_async *); unsigned int comedi_buf_read_alloc(struct comedi_async *, unsigned int); unsigned int comedi_buf_read_free(struct comedi_async *, unsigned int); -int comedi_buf_put(struct comedi_async *, short); -int comedi_buf_get(struct comedi_async *, short *); +int comedi_buf_put(struct comedi_async *, unsigned short); +int comedi_buf_get(struct comedi_async *, unsigned short *); void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, const void *source, unsigned int num_bytes); @@ -345,6 +359,8 @@ void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *data, unsigned int mask); +unsigned int comedi_dio_update_state(struct comedi_subdevice *, + unsigned int *data); void *comedi_alloc_devpriv(struct comedi_device *, size_t); int comedi_alloc_subdevices(struct comedi_device *, int); diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 317a821b7906..8f02bf66e20b 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -190,6 +190,28 @@ int comedi_dio_insn_config(struct comedi_device *dev, } EXPORT_SYMBOL_GPL(comedi_dio_insn_config); +/** + * comedi_dio_update_state() - update the internal state of DIO subdevices. + * @s: comedi_subdevice struct + * @data: the channel mask and bits to update + */ +unsigned int comedi_dio_update_state(struct comedi_subdevice *s, + unsigned int *data) +{ + unsigned int chanmask = (s->n_chan < 32) ? ((1 << s->n_chan) - 1) + : 0xffffffff; + unsigned int mask = data[0] & chanmask; + unsigned int bits = data[1]; + + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + } + + return mask; +} +EXPORT_SYMBOL_GPL(comedi_dio_update_state); + static int insn_rw_emulate_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -285,6 +307,13 @@ static int __comedi_device_postconfig(struct comedi_device *dev) if (s->type == COMEDI_SUBD_UNUSED) continue; + if (s->type == COMEDI_SUBD_DO) { + if (s->n_chan < 32) + s->io_bits = (1 << s->n_chan) - 1; + else + s->io_bits = 0xffffffff; + } + if (s->len_chanlist == 0) s->len_chanlist = 1; diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index 3abedcd2527b..e3d737cf7302 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -21,6 +21,15 @@ #include "../comedi.h" +/* + * Common oscillator base values in nanoseconds + */ +#define I8254_OSC_BASE_10MHZ 100 +#define I8254_OSC_BASE_5MHZ 200 +#define I8254_OSC_BASE_4MHZ 250 +#define I8254_OSC_BASE_2MHZ 500 +#define I8254_OSC_BASE_1MHZ 1000 + #define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div static inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base, diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index 2f070fdbbb1d..b4009e863414 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -112,7 +112,7 @@ void subdev_8255_interrupt(struct comedi_device *dev, { struct subdev_8255_private *spriv = s->private; unsigned long iobase = spriv->iobase; - short d; + unsigned short d; d = spriv->io(0, _8255_DATA, 0, iobase); d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8); @@ -126,30 +126,24 @@ EXPORT_SYMBOL_GPL(subdev_8255_interrupt); static int subdev_8255_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct subdev_8255_private *spriv = s->private; unsigned long iobase = spriv->iobase; unsigned int mask; - unsigned int bits; unsigned int v; - mask = data[0]; - bits = data[1]; - + mask = comedi_dio_update_state(s, data); if (mask) { - v = s->state; - v &= ~mask; - v |= (bits & mask); - if (mask & 0xff) - spriv->io(1, _8255_DATA, v & 0xff, iobase); + spriv->io(1, _8255_DATA, s->state & 0xff, iobase); if (mask & 0xff00) - spriv->io(1, _8255_DATA + 1, (v >> 8) & 0xff, iobase); + spriv->io(1, _8255_DATA + 1, (s->state >> 8) & 0xff, + iobase); if (mask & 0xff0000) - spriv->io(1, _8255_DATA + 2, (v >> 16) & 0xff, iobase); - - s->state = v; + spriv->io(1, _8255_DATA + 2, (s->state >> 16) & 0xff, + iobase); } v = spriv->io(0, _8255_DATA, 0, iobase); @@ -288,9 +282,6 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, s->insn_bits = subdev_8255_insn; s->insn_config = subdev_8255_insn_config; - s->state = 0; - s->io_bits = 0; - subdev_8255_do_config(dev, s); return 0; diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index 63dff7729ea8..dc87df032203 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -204,7 +204,6 @@ static int addi_auto_attach(struct comedi_device *dev, s->len_chanlist = devpriv->s_EeParameters.i_NbrDiChannel; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_config = this_board->di_config; s->insn_read = this_board->di_read; s->insn_write = this_board->di_write; @@ -223,7 +222,6 @@ static int addi_auto_attach(struct comedi_device *dev, s->len_chanlist = devpriv->s_EeParameters.i_NbrDoChannel; s->range_table = &range_digital; - s->io_bits = 0xf; /* all bits output */ /* insn_config - for digital output memory */ s->insn_config = this_board->do_config; diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h index dfd1e666cc18..2ed2da3499f4 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -133,7 +133,7 @@ struct addi_private { unsigned short us_UseDma; /* To use Dma or not */ unsigned char b_DmaDoubleBuffer; /* we can use double buffering */ unsigned int ui_DmaActualBuffer; /* which buffer is used now */ - short *ul_DmaBufferVirtual[2]; /* pointers to begin of DMA buffer */ + unsigned short *ul_DmaBufferVirtual[2]; /* pointers to DMA buffer */ unsigned int ul_DmaBufferHw[2]; /* hw address of DMA buff */ unsigned int ui_DmaBufferSize[2]; /* size of dma buffer in bytes */ unsigned int ui_DmaBufferUsesize[2]; /* which size we may now used for transfer */ diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index e3cc429403c0..84668544f52d 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -260,18 +260,13 @@ static int apci1564_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_RW); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_RW); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index 1449b92403e2..3c9eec84f0eb 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -1391,7 +1391,7 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, */ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, struct comedi_subdevice *s, - short *dma_buffer, + unsigned short *dma_buffer, unsigned int num_samples) { struct addi_private *devpriv = dev->private; @@ -2175,21 +2175,16 @@ static int apci3120_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - unsigned int val; - /* The do channels are bits 7:4 of the do register */ - val = devpriv->b_DigitalOutputRegister >> 4; - if (mask) { - val &= ~mask; - val |= (bits & mask); - devpriv->b_DigitalOutputRegister = val << 4; + if (comedi_dio_update_state(s, data)) { + /* The do channels are bits 7:4 of the do register */ + devpriv->b_DigitalOutputRegister = s->state << 4; - outb(val << 4, devpriv->iobase + APCI3120_DIGITAL_OUTPUT); + outb(devpriv->b_DigitalOutputRegister, + devpriv->iobase + APCI3120_DIGITAL_OUTPUT); } - data[1] = val; + data[1] = s->state; return insn->n; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index 32dce0329fd5..dc73d4d348ed 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -623,16 +623,11 @@ static int apci3200_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; s->state = inl(devpriv->i_IobaseAddon) & 0xf; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, devpriv->i_IobaseAddon); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c index 08674c18cf42..9d1b1425c60b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1516.c +++ b/drivers/staging/comedi/drivers/addi_apci_1516.c @@ -90,16 +90,10 @@ static int apci1516_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - s->state = inw(dev->iobase + APCI1516_DO_REG); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + APCI1516_DO_REG); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c index 96523744b8de..5ee204bcbeef 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c @@ -87,17 +87,8 @@ static int apci16xx_dio_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - /* Only update the channels configured as outputs */ - mask &= s->io_bits; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + APCI16XX_OUT_REG(s->index)); - } data[1] = inl(dev->iobase + APCI16XX_IN_REG(s->index)); diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index 6b0ea16ff546..c77ee8732d38 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -57,16 +57,10 @@ static int apci2032_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - s->state = inl(dev->iobase + APCI2032_DO_REG); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + APCI2032_DO_REG); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c index 92ac8ece8494..7fb32e778d8b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2200.c +++ b/drivers/staging/comedi/drivers/addi_apci_2200.c @@ -50,16 +50,10 @@ static int apci2200_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - s->state = inw(dev->iobase + APCI2200_DO_REG); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + APCI2200_DO_REG); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index d804957018ab..67d09e8afb2e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -164,7 +164,6 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = this_board->i_NbrDiChannel; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_bits = apci3120_di_insn_bits; /* Allocate and Initialise DO Subdevice Structures */ @@ -176,7 +175,6 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->maxdata = this_board->i_DoMaxdata; s->len_chanlist = this_board->i_NbrDoChannel; s->range_table = &range_digital; - s->io_bits = 0xf; /* all bits output */ s->insn_bits = apci3120_do_insn_bits; /* Allocate and Initialise Timer Subdevice Structures */ diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index d9650ffb7d2f..6138440b919e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -161,16 +161,10 @@ static int apci3501_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - s->state = inl(dev->iobase + APCI3501_DO_REG); - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + APCI3501_DO_REG); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index cf5dd10eaf91..761cbf8f964b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -664,16 +664,10 @@ static int apci3xxx_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - s->state = inl(dev->iobase + 48) & 0xf; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + 48); - } data[1] = s->state; @@ -717,16 +711,11 @@ static int apci3xxx_dio_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; + unsigned int mask; unsigned int val; - /* only update output channels */ - mask &= s->io_bits; + mask = comedi_dio_update_state(s, data); if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - if (mask & 0xff) outl(s->state & 0xff, dev->iobase + 80); if (mask & 0xff0000) diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index a67ad57cefcb..dd092c7954a9 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -1,44 +1,35 @@ /* - comedi/drivers/adl_pci6208.c - - Hardware driver for ADLink 6208 series cards: - card | voltage output | current output - -------------+-------------------+--------------- - PCI-6208V | 8 channels | - - PCI-6216V | 16 channels | - - PCI-6208A | 8 channels | 8 channels - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.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, 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. -*/ + * adl_pci6208.c + * Comedi driver for ADLink 6208 series cards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.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, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* -Driver: adl_pci6208 -Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards -Devices: (ADLink) PCI-6208 [adl_pci6208] - (ADLink) PCI-6216 [adl_pci6216] -Author: nsyeow <nsyeow@pd.jaring.my> -Updated: Fri, 30 Jan 2004 14:44:27 +0800 -Status: untested - -Configuration Options: not applicable, uses PCI auto config - -References: - - ni_660x.c - - adl_pci9111.c copied the entire pci setup section - - adl_pci9118.c -*/ + * Driver: adl_pci6208 + * Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards + * Devices: (ADLink) PCI-6208 [adl_pci6208] + * (ADLink) PCI-6216 [adl_pci6216] + * Author: nsyeow <nsyeow@pd.jaring.my> + * Updated: Fri, 30 Jan 2004 14:44:27 +0800 + * Status: untested + * + * Configuration Options: not applicable, uses PCI auto config + */ #include <linux/module.h> +#include <linux/delay.h> #include <linux/pci.h> #include "../comedidev.h" @@ -82,37 +73,56 @@ struct pci6208_private { unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS]; }; -static int pci6208_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pci6208_ao_wait_for_data_send(struct comedi_device *dev, + unsigned int timeout) +{ + unsigned int status; + + while (timeout--) { + status = inw(dev->iobase + PCI6208_AO_STATUS); + if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) + return 0; + udelay(1); + } + + return -ETIME; +} + +static int pci6208_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pci6208_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - unsigned long invert = 1 << (16 - 1); - unsigned long value = 0; - unsigned short status; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int ret; int i; for (i = 0; i < insn->n; i++) { - value = data[i] ^ invert; + val = data[i]; - do { - status = inw(dev->iobase + PCI6208_AO_STATUS); - } while (status & PCI6208_AO_STATUS_DATA_SEND); + /* D/A transfer rate is 2.2us, wait up to 10us */ + ret = pci6208_ao_wait_for_data_send(dev, 10); + if (ret) + return ret; - outw(value, dev->iobase + PCI6208_AO_CONTROL(chan)); + /* the hardware expects two's complement values */ + outw(comedi_offset_munge(s, val), + dev->iobase + PCI6208_AO_CONTROL(chan)); } - devpriv->ao_readback[chan] = value; + devpriv->ao_readback[chan] = val; return insn->n; } -static int pci6208_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pci6208_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pci6208_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); int i; for (i = 0; i < insn->n; i++) @@ -141,15 +151,8 @@ static int pci6208_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI6208_DIO); - } data[1] = s->state; @@ -193,8 +196,8 @@ static int pci6208_auto_attach(struct comedi_device *dev, s->n_chan = boardinfo->ao_chans; s->maxdata = 0xffff; s->range_table = &range_bipolar10; - s->insn_write = pci6208_ao_winsn; - s->insn_read = pci6208_ao_rinsn; + s->insn_write = pci6208_ao_insn_write; + s->insn_read = pci6208_ao_insn_read; s = &dev->subdevices[1]; /* digital input subdevice */ @@ -221,10 +224,6 @@ static int pci6208_auto_attach(struct comedi_device *dev, val = inw(dev->iobase + PCI6208_DIO); val = (val & PCI6208_DIO_DO_MASK) >> PCI6208_DIO_DO_SHIFT; s->state = val; - s->io_bits = 0x0f; - - dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx\n", - dev->driver->driver_name, dev->board_name, dev->iobase); return 0; } @@ -259,5 +258,5 @@ static struct pci_driver adl_pci6208_pci_driver = { module_comedi_pci_driver(adl_pci6208_driver, adl_pci6208_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for ADLink 6208 series cards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index 81b7203f824f..5617f5ca384a 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -112,21 +112,10 @@ static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev, unsigned int *data) { unsigned long reg = (unsigned long)s->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) outl(s->state, dev->iobase + reg); - } - /* - * NOTE: The output register is not readable. - * This returned state will not be correct until all the - * outputs have been updated. - */ data[1] = s->state; return insn->n; diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index 78cea193504f..eab8da2c3d66 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -86,8 +86,6 @@ TODO: #define PCI9111_AI_INSTANT_READ_UDELAY_US 2 #define PCI9111_AI_INSTANT_READ_TIMEOUT 100 -#define PCI9111_8254_CLOCK_PERIOD_NS 500 - /* * IO address map and bit defines */ @@ -153,7 +151,7 @@ struct pci9111_private_data { unsigned int div1; unsigned int div2; - short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; + unsigned short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; }; static void plx9050_interrupt_control(unsigned long io_base, @@ -393,11 +391,10 @@ static int pci9111_ai_do_cmd_test(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, - &dev_private->div1, - &dev_private->div2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &dev_private->div1, + &dev_private->div2, + &cmd->convert_arg, cmd->flags); if (tmp != cmd->convert_arg) error++; } @@ -570,7 +567,7 @@ static void pci9111_ai_munge(struct comedi_device *dev, unsigned int num_bytes, unsigned int start_chan_index) { - short *array = data; + unsigned short *array = data; unsigned int maxdata = s->maxdata; unsigned int invert = (maxdata + 1) >> 1; unsigned int shift = (maxdata == 0xffff) ? 0 : 4; @@ -813,15 +810,8 @@ static int pci9111_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI9111_DIO_REG); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 22196ada0362..0f2e8591c697 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -352,12 +352,11 @@ struct pci9118_private { * on external start */ unsigned int ai_data_len; - short *ai_data; - short ao_data[2]; /* data output buffer */ + unsigned short ao_data[2]; /* data output buffer */ unsigned int ai_scans; /* number of scans to do */ char dma_doublebuf; /* we can use double buffering */ unsigned int dma_actbuf; /* which buffer is used now */ - short *dmabuf_virt[2]; /* + unsigned short *dmabuf_virt[2]; /* * pointers to begin of * DMA buffer */ @@ -671,13 +670,12 @@ static int pci9118_insn_bits_di(struct comedi_device *dev, static int pci9118_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outl(s->state & 0x0f, dev->iobase + PCI9118_DO); - } + data[1] = s->state; return insn->n; @@ -701,7 +699,7 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev) static unsigned int defragment_dma_buffer(struct comedi_device *dev, struct comedi_subdevice *s, - short *dma_buffer, + unsigned short *dma_buffer, unsigned int num_samples) { struct pci9118_private *devpriv = dev->private; @@ -725,7 +723,7 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev, static int move_block_from_dma(struct comedi_device *dev, struct comedi_subdevice *s, - short *dma_buffer, + unsigned short *dma_buffer, unsigned int num_samples) { struct pci9118_private *devpriv = dev->private; @@ -793,7 +791,8 @@ static void pci9118_calc_divisors(char mode, struct comedi_device *dev, case 4: if (*tim2 < this_board->ai_ns_min) *tim2 = this_board->ai_ns_min; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, div1, div2, + i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, + div1, div2, tim2, flags & TRIG_ROUND_NEAREST); break; case 2: @@ -925,7 +924,7 @@ static void pci9118_ai_munge(struct comedi_device *dev, { struct pci9118_private *devpriv = dev->private; unsigned int i, num_samples = num_bytes / sizeof(short); - short *array = data; + unsigned short *array = data; for (i = 0; i < num_samples; i++) { if (devpriv->usedma) @@ -945,7 +944,7 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, unsigned short int_daq) { struct pci9118_private *devpriv = dev->private; - register short sampl; + unsigned short sampl; s->async->events = 0; @@ -1278,9 +1277,9 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) { tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, + &divisor1, &divisor2, + &cmd->scan_begin_arg, cmd->flags); if (cmd->scan_begin_arg < this_board->ai_ns_min) cmd->scan_begin_arg = this_board->ai_ns_min; if (tmp != cmd->scan_begin_arg) @@ -1289,9 +1288,9 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, + &divisor1, &divisor2, + &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < this_board->ai_ns_min) cmd->convert_arg = this_board->ai_ns_min; if (tmp != cmd->convert_arg) @@ -1613,7 +1612,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_n_scanlen = cmd->scan_end_arg; devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_data = s->async->prealloc_buf; devpriv->ai_data_len = s->async->prealloc_bufsz; devpriv->ai_timer1 = 0; devpriv->ai_timer2 = 0; @@ -1987,8 +1985,8 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, for (i = 0; i < 2; i++) { for (pages = 4; pages >= 0; pages--) { devpriv->dmabuf_virt[i] = - (short *)__get_free_pages(GFP_KERNEL, - pages); + (unsigned short *) + __get_free_pages(GFP_KERNEL, pages); if (devpriv->dmabuf_virt[i]) break; } @@ -2075,7 +2073,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, s->maxdata = 1; s->len_chanlist = 4; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_bits = pci9118_insn_bits_di; s = &dev->subdevices[3]; @@ -2085,11 +2082,10 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, s->maxdata = 1; s->len_chanlist = 4; s->range_table = &range_digital; - s->io_bits = 0xf; /* all bits output */ s->insn_bits = pci9118_insn_bits_do; devpriv->valid = 1; - devpriv->i8254_osc_base = 250; /* 250ns=4MHz */ + devpriv->i8254_osc_base = I8254_OSC_BASE_4MHZ; devpriv->ai_maskharderr = 0x10a; /* default measure crash condition */ if (hw_err_mask) /* disable some requested */ diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index cdf5ba26c590..8150a67cd1fb 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -119,7 +119,6 @@ struct adq12b_private { int differential; /* option 3 of comedi_config */ int last_channel; int last_range; - unsigned int digital_state; }; /* @@ -186,23 +185,25 @@ static int adq12b_di_insn_bits(struct comedi_device *dev, static int adq12b_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct adq12b_private *devpriv = dev->private; - int channel; - - for (channel = 0; channel < 8; channel++) - if (((data[0] >> channel) & 0x01) != 0) - outb((((data[1] >> channel) & 0x01) << 3) | channel, - dev->iobase + ADQ12B_OUTBR); - - /* store information to retrieve when asked for reading */ - if (data[0]) { - devpriv->digital_state &= ~data[0]; - devpriv->digital_state |= (data[0] & data[1]); + unsigned int mask; + unsigned int chan; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + for (chan = 0; chan < 8; chan++) { + if ((mask >> chan) & 0x01) { + val = (s->state >> chan) & 0x01; + outb((val << 3) | chan, + dev->iobase + ADQ12B_OUTBR); + } + } } - data[1] = devpriv->digital_state; + data[1] = s->state; return insn->n; } @@ -223,7 +224,6 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->unipolar = it->options[1]; devpriv->differential = it->options[2]; - devpriv->digital_state = 0; /* * initialize channel and range to -1 so we make sure we * always write at least once to the CTREG in the instruction diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index f84df46d326a..c3fdcabe9aec 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -314,10 +314,9 @@ struct pci1710_private { unsigned int *ai_chanlist; /* actaul chanlist */ unsigned int ai_flags; /* flaglist */ unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ unsigned int ai_timer1; /* timers */ unsigned int ai_timer2; - short ao_data[4]; /* data output buffer */ + unsigned short ao_data[4]; /* data output buffer */ unsigned int cnt0_write_wait; /* after a write, wait for update of the * internal state */ }; @@ -544,18 +543,14 @@ static int pci171x_insn_bits_di(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static int pci171x_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI171x_DO); - } + data[1] = s->state; return insn->n; @@ -740,7 +735,7 @@ static void interrupt_pci1710_every_sample(void *d) int m; #ifdef PCI171x_PARANOIDCHECK const struct boardtype *this_board = comedi_board(dev); - short sampl; + unsigned short sampl; #endif m = inw(dev->iobase + PCI171x_STATUS); @@ -821,7 +816,7 @@ static int move_block_from_fifo(struct comedi_device *dev, int i, j; #ifdef PCI171x_PARANOIDCHECK const struct boardtype *this_board = comedi_board(dev); - int sampl; + unsigned short sampl; #endif j = s->async->cur_chan; @@ -1009,9 +1004,10 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, } else { devpriv->ai_et = 0; } - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &devpriv->ai_timer1, - devpriv->ai_flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, + &divisor1, &divisor2, + &devpriv->ai_timer1, + devpriv->ai_flags); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); if (mode != 2) { /* start pacer */ @@ -1090,9 +1086,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, + &divisor1, &divisor2, + &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < this_board->ai_ns_min) cmd->convert_arg = this_board->ai_ns_min; if (tmp != cmd->convert_arg) @@ -1125,7 +1121,6 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_chanlist = cmd->chanlist; devpriv->ai_flags = cmd->flags; devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; devpriv->ai_timer1 = 0; devpriv->ai_timer2 = 0; @@ -1288,7 +1283,7 @@ static int pci1710_auto_attach(struct comedi_device *dev, s->do_cmdtest = pci171x_ai_cmdtest; s->do_cmd = pci171x_ai_cmd; } - devpriv->i8254_osc_base = 100; /* 100ns=10MHz */ + devpriv->i8254_osc_base = I8254_OSC_BASE_10MHZ; subdev++; } @@ -1320,7 +1315,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = this_board->n_dichan; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_bits = pci171x_insn_bits_di; subdev++; } @@ -1333,9 +1327,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = this_board->n_dochan; s->range_table = &range_digital; - /* all bits output */ - s->io_bits = (1 << this_board->n_dochan) - 1; - s->state = 0; s->insn_bits = pci171x_insn_bits_do; subdev++; } diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index b793d6987b84..bd4f781b4b24 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -105,7 +105,7 @@ TODO: struct pci1723_private { unsigned char da_range[8]; /* D/A output range for each channel */ - short ao_data[8]; /* data output buffer */ + unsigned short ao_data[8]; /* data output buffer */ }; /* @@ -205,19 +205,16 @@ static int pci1723_dio_insn_config(struct comedi_device *dev, return insn->n; } -/* - digital i/o bits read/write -*/ static int pci1723_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI1723_WRITE_DIGITAL_OUTPUT_CMD); - } + data[1] = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); + return insn->n; } diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index f091fa0d304d..6bac665261f8 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -448,45 +448,39 @@ static int pci_dio_insn_bits_di_w(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static int pci_dio_insn_bits_do_b(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { for (i = 0; i < d->regs; i++) outb((s->state >> (8 * i)) & 0xff, dev->iobase + d->addr + i); } + data[1] = s->state; return insn->n; } -/* -============================================================================== -*/ static int pci_dio_insn_bits_do_w(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { for (i = 0; i < d->regs; i++) outw((s->state >> (16 * i)) & 0xffff, dev->iobase + d->addr + 2 * i); } + data[1] = s->state; return insn->n; @@ -641,12 +635,10 @@ static int pci1760_insn_bits_di(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static int pci1760_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { int ret; unsigned char omb[4] = { @@ -657,14 +649,13 @@ static int pci1760_insn_bits_do(struct comedi_device *dev, }; unsigned char imb[4]; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { omb[0] = s->state; ret = pci1760_mbxrequest(dev, omb, imb); if (!ret) return ret; } + data[1] = s->state; return insn->n; diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index afe87cc89761..22b3dda135ff 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -45,9 +45,7 @@ static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + if (comedi_dio_update_state(s, data)) { outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7); outb((s->state >> 8) & 0xff, dev->iobase + AIO_IIRO_16_RELAY_8_15); diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index c1f723e86146..2e4bf284d52c 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -941,31 +941,34 @@ static void dio200_subdev_8255_set_dir(struct comedi_device *dev, dio200_write8(dev, subpriv->ofs + 3, config); } -/* - * Handle 'insn_bits' for an '8255' DIO subdevice. - */ static int dio200_subdev_8255_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct dio200_subdev_8255 *subpriv = s->private; + unsigned int mask; + unsigned int val; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - if (data[0] & 0xff) + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0xff) dio200_write8(dev, subpriv->ofs, s->state & 0xff); - if (data[0] & 0xff00) + if (mask & 0xff00) dio200_write8(dev, subpriv->ofs + 1, (s->state >> 8) & 0xff); - if (data[0] & 0xff0000) + if (mask & 0xff0000) dio200_write8(dev, subpriv->ofs + 2, (s->state >> 16) & 0xff); } - data[1] = dio200_read8(dev, subpriv->ofs); - data[1] |= dio200_read8(dev, subpriv->ofs + 1) << 8; - data[1] |= dio200_read8(dev, subpriv->ofs + 2) << 16; - return 2; + + val = dio200_read8(dev, subpriv->ofs); + val |= dio200_read8(dev, subpriv->ofs + 1) << 8; + val |= dio200_read8(dev, subpriv->ofs + 2) << 16; + + data[1] = val; + + return insn->n; } /* @@ -1022,8 +1025,6 @@ static int dio200_subdev_8255_init(struct comedi_device *dev, s->maxdata = 1; s->insn_bits = dio200_subdev_8255_bits; s->insn_config = dio200_subdev_8255_config; - s->state = 0; - s->io_bits = 0; dio200_subdev_8255_set_dir(dev, s); return 0; } diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index e7108045f553..5b4b5ab34e2e 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -57,17 +57,16 @@ static const struct pc263_board pc263_boards[] = { static int pc263_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - outb(s->state & 0xFF, dev->iobase); - outb(s->state >> 8, dev->iobase + 1); + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase); + outb((s->state >> 8) & 0xff, dev->iobase + 1); } + + data[1] = s->state; + return insn->n; } diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 179de53a86f0..810e397d8fd7 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -215,12 +215,6 @@ Caveats: #define CLK_EXT 7 /* external clock */ /* Macro to construct clock input configuration register value. */ #define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7)) -/* Timebases in ns. */ -#define TIMEBASE_10MHZ 100 -#define TIMEBASE_1MHZ 1000 -#define TIMEBASE_100KHZ 10000 -#define TIMEBASE_10KHZ 100000 -#define TIMEBASE_1KHZ 1000000 /* * Counter/timer gate input configuration sources. @@ -379,7 +373,7 @@ struct pci224_private { unsigned long state; spinlock_t ao_spinlock; unsigned int *ao_readback; - short *ao_scan_vals; + unsigned short *ao_scan_vals; unsigned char *ao_scan_order; int intr_cpuid; short intr_running; @@ -843,26 +837,26 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, switch (round_mode) { case TRIG_ROUND_NEAREST: default: - round = TIMEBASE_10MHZ / 2; + round = I8254_OSC_BASE_10MHZ / 2; break; case TRIG_ROUND_DOWN: round = 0; break; case TRIG_ROUND_UP: - round = TIMEBASE_10MHZ - 1; + round = I8254_OSC_BASE_10MHZ - 1; break; } /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / TIMEBASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % TIMEBASE_10MHZ) / - TIMEBASE_10MHZ; + div2 = cmd->scan_begin_arg / I8254_OSC_BASE_10MHZ; + div2 += (round + cmd->scan_begin_arg % I8254_OSC_BASE_10MHZ) / + I8254_OSC_BASE_10MHZ; if (div2 <= 0x10000) { /* A single timer will suffice. */ if (div2 < 2) div2 = 2; - cmd->scan_begin_arg = div2 * TIMEBASE_10MHZ; + cmd->scan_begin_arg = div2 * I8254_OSC_BASE_10MHZ; if (cmd->scan_begin_arg < div2 || - cmd->scan_begin_arg < TIMEBASE_10MHZ) { + cmd->scan_begin_arg < I8254_OSC_BASE_10MHZ) { /* Overflow! */ cmd->scan_begin_arg = MAX_SCAN_PERIOD; } @@ -870,7 +864,8 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Use two timers. */ div1 = devpriv->cached_div1; div2 = devpriv->cached_div2; - pci224_cascade_ns_to_timer(TIMEBASE_10MHZ, &div1, &div2, + pci224_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &div1, &div2, &cmd->scan_begin_arg, round_mode); devpriv->cached_div1 = div1; @@ -1002,19 +997,19 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) switch (round_mode) { case TRIG_ROUND_NEAREST: default: - round = TIMEBASE_10MHZ / 2; + round = I8254_OSC_BASE_10MHZ / 2; break; case TRIG_ROUND_DOWN: round = 0; break; case TRIG_ROUND_UP: - round = TIMEBASE_10MHZ - 1; + round = I8254_OSC_BASE_10MHZ - 1; break; } /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / TIMEBASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % TIMEBASE_10MHZ) / - TIMEBASE_10MHZ; + div2 = cmd->scan_begin_arg / I8254_OSC_BASE_10MHZ; + div2 += (round + cmd->scan_begin_arg % I8254_OSC_BASE_10MHZ) / + I8254_OSC_BASE_10MHZ; if (div2 <= 0x10000) { /* A single timer will suffice. */ if (div2 < 2) @@ -1025,7 +1020,8 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* Use two timers. */ div1 = devpriv->cached_div1; div2 = devpriv->cached_div2; - pci224_cascade_ns_to_timer(TIMEBASE_10MHZ, &div1, &div2, + pci224_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &div1, &div2, &ns, round_mode); } @@ -1116,7 +1112,7 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, const struct pci224_board *thisboard = comedi_board(dev); struct pci224_private *devpriv = dev->private; struct comedi_async *async = s->async; - short *array = data; + unsigned short *array = data; unsigned int length = num_bytes / sizeof(*array); unsigned int offset; unsigned int shift; diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 43059c25d5ea..a97bbd6ca3db 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -573,14 +573,14 @@ static const struct comedi_lrange pci230_ao_range = { 2, { /* PCI230 daccon bipolar flag for each analogue output range. */ static const unsigned char pci230_ao_bipolar[2] = { 0, 1 }; -static short pci230_ai_read(struct comedi_device *dev) +static unsigned short pci230_ai_read(struct comedi_device *dev) { const struct pci230_board *thisboard = comedi_board(dev); struct pci230_private *devpriv = dev->private; - short data; + unsigned short data; /* Read sample. */ - data = (short)inw(dev->iobase + PCI230_ADCDATA); + data = inw(dev->iobase + PCI230_ADCDATA); /* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower * four bits reserved for expansion). */ /* PCI230+ is 16 bit AI. */ @@ -595,7 +595,7 @@ static short pci230_ai_read(struct comedi_device *dev) } static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, - short datum) + unsigned short datum) { const struct pci230_board *thisboard = comedi_board(dev); struct pci230_private *devpriv = dev->private; @@ -609,11 +609,12 @@ static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, * four bits reserved for expansion). */ /* PCI230+ is also 12 bit AO. */ datum <<= (16 - thisboard->ao_bits); - return (unsigned short)datum; + return datum; } static inline void pci230_ao_write_nofifo(struct comedi_device *dev, - short datum, unsigned int chan) + unsigned short datum, + unsigned int chan) { struct pci230_private *devpriv = dev->private; @@ -627,8 +628,8 @@ static inline void pci230_ao_write_nofifo(struct comedi_device *dev, PCI230_DACOUT2)); } -static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum, - unsigned int chan) +static inline void pci230_ao_write_fifo(struct comedi_device *dev, + unsigned short datum, unsigned int chan) { struct pci230_private *devpriv = dev->private; @@ -1165,7 +1166,7 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev, struct comedi_subdevice *s) { struct pci230_private *devpriv = dev->private; - short data; + unsigned short data; int i, ret; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -1258,7 +1259,7 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev, /* Process scans. */ for (n = 0; n < num_scans; n++) { for (i = 0; i < cmd->chanlist_len; i++) { - short datum; + unsigned short datum; comedi_buf_get(async, &datum); pci230_ao_write_fifo(dev, datum, diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c index 145bb48f618e..4bd4ef8e88cd 100644 --- a/drivers/staging/comedi/drivers/amplc_pci263.c +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -44,17 +44,16 @@ The state of the outputs can be read. static int pci263_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - outb(s->state & 0xFF, dev->iobase); - outb(s->state >> 8, dev->iobase + 1); + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase); + outb((s->state >> 8) & 0xff, dev->iobase + 1); } + + data[1] = s->state; + return insn->n; } diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 0ce93da70847..64d5f291553f 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -234,9 +234,9 @@ static int das16cs_ai_cmdtest(struct comedi_device *dev, unsigned int div1 = 0, div2 = 0; tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(100, &div1, &div2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &div1, &div2, + &cmd->scan_begin_arg, cmd->flags); if (tmp != cmd->scan_begin_arg) err++; } @@ -244,9 +244,9 @@ static int das16cs_ai_cmdtest(struct comedi_device *dev, unsigned int div1 = 0, div2 = 0; tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(100, &div1, &div2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &div1, &div2, + &cmd->scan_begin_arg, cmd->flags); if (tmp != cmd->convert_arg) err++; if (cmd->scan_begin_src == TRIG_TIMER && @@ -325,14 +325,11 @@ static int das16cs_ao_rinsn(struct comedi_device *dev, static int das16cs_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + DAS16CS_DIO); - } data[1] = inw(dev->iobase + DAS16CS_DIO); diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 41d89ee7fa33..e72a403db17c 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -73,7 +73,6 @@ analog triggering on 1602 series #include "amcc_s5933.h" #include "comedi_fc.h" -#define TIMER_BASE 100 /* 10MHz master clock */ #define AI_BUFFER_SIZE 1024 /* max ai fifo size */ #define AO_BUFFER_SIZE 1024 /* max ao fifo size */ #define NUM_CHANNELS_8800 8 @@ -358,15 +357,15 @@ struct cb_pcidas_private { unsigned int s5933_intcsr_bits; unsigned int ao_control_bits; /* fifo buffers */ - short ai_buffer[AI_BUFFER_SIZE]; - short ao_buffer[AO_BUFFER_SIZE]; + unsigned short ai_buffer[AI_BUFFER_SIZE]; + unsigned short ao_buffer[AO_BUFFER_SIZE]; /* divisors of master clock for analog output pacing */ unsigned int ao_divisor1; unsigned int ao_divisor2; /* number of analog output samples remaining */ unsigned int ao_count; /* cached values for readback */ - int ao_value[2]; + unsigned short ao_value[2]; unsigned int caldac_value[NUM_CHANNELS_8800]; unsigned int trimpot_value[NUM_CHANNELS_8402]; unsigned int dac08_value; @@ -880,21 +879,19 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) { tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->scan_begin_arg), - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->scan_begin_arg, cmd->flags); if (tmp != cmd->scan_begin_arg) err++; } if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->convert_arg, cmd->flags); if (tmp != cmd->convert_arg) err++; } @@ -932,9 +929,9 @@ static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns, { struct cb_pcidas_private *devpriv = dev->private; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), - &(devpriv->divisor2), ns, - rounding_flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, &devpriv->divisor2, + ns, rounding_flags); /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 1, @@ -1084,11 +1081,10 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) { tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->ao_divisor1), - &(devpriv->ao_divisor2), - &(cmd->scan_begin_arg), - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->ao_divisor1, + &devpriv->ao_divisor2, + &cmd->scan_begin_arg, cmd->flags); if (tmp != cmd->scan_begin_arg) err++; } @@ -1209,11 +1205,10 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, /* load counters */ if (cmd->scan_begin_src == TRIG_TIMER) { - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->ao_divisor1), - &(devpriv->ao_divisor2), - &(cmd->scan_begin_arg), - cmd->flags); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->ao_divisor1, + &devpriv->ao_divisor2, + &cmd->scan_begin_arg, cmd->flags); /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1, diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 388dbd7a5d27..ff5206536be3 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1137,7 +1137,7 @@ struct pcidas64_private { volatile short ai_cmd_running; unsigned int ai_fifo_segment_length; struct ext_clock_info ext_clock; - short ao_bounce_buffer[DAC_FIFO_SIZE]; + unsigned short ao_bounce_buffer[DAC_FIFO_SIZE]; }; static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, @@ -3490,18 +3490,15 @@ static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int do_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pcidas64_private *devpriv = dev->private; - data[0] &= 0xf; - /* zero bits we are going to change */ - s->state &= ~data[0]; - /* set new bits */ - s->state |= data[0] & data[1]; - - writeb(s->state, devpriv->dio_counter_iobase + DO_REG); + if (comedi_dio_update_state(s, data)) + writeb(s->state, devpriv->dio_counter_iobase + DO_REG); data[1] = s->state; @@ -3526,14 +3523,14 @@ static int dio_60xx_config_insn(struct comedi_device *dev, return insn->n; } -static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dio_60xx_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct pcidas64_private *devpriv = dev->private; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { writeb(s->state, devpriv->dio_counter_iobase + DIO_DATA_60XX_REG); } diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index a4dea7cb86be..8558b07f8df3 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -30,7 +30,7 @@ extern unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, unsigned int num_bytes); static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *subd, - short data) + unsigned short data) { return cfc_write_array_to_buffer(subd, &data, sizeof(data)); }; diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index f28a15f0274e..9de81c7712fb 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -1,168 +1,153 @@ /* - comedi/drivers/comedi_parport.c - hardware driver for standard parallel port - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998,2001 David A. Schleef <ds@schleef.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, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: comedi_parport -Description: Standard PC parallel port -Author: ds -Status: works in immediate mode -Devices: [standard] parallel port (comedi_parport) -Updated: Tue, 30 Apr 2002 21:11:45 -0700 - -A cheap and easy way to get a few more digital I/O lines. Steal -additional parallel ports from old computers or your neighbors' -computers. - -Option list: - 0: I/O port base for the parallel port. - 1: IRQ - -Parallel Port Lines: - -pin subdev chan aka ---- ------ ---- --- -1 2 0 strobe -2 0 0 data 0 -3 0 1 data 1 -4 0 2 data 2 -5 0 3 data 3 -6 0 4 data 4 -7 0 5 data 5 -8 0 6 data 6 -9 0 7 data 7 -10 1 3 acknowledge -11 1 4 busy -12 1 2 output -13 1 1 printer selected -14 2 1 auto LF -15 1 0 error -16 2 2 init -17 2 3 select printer -18-25 ground - -Notes: - -Subdevices 0 is digital I/O, subdevice 1 is digital input, and -subdevice 2 is digital output. Unlike other Comedi devices, -subdevice 0 defaults to output. - -Pins 13 and 14 are inverted once by Comedi and once by the -hardware, thus cancelling the effect. - -Pin 1 is a strobe, thus acts like one. There's no way in software -to change this, at least on a standard parallel port. - -Subdevice 3 pretends to be a digital input subdevice, but it always -returns 0 when read. However, if you run a command with -scan_begin_src=TRIG_EXT, it uses pin 10 as a external triggering -pin, which can be used to wake up tasks. -*/ + * comedi_parport.c + * Comedi driver for standard parallel port + * + * For more information see: + * http://retired.beyondlogic.org/spp/parallel.htm + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998,2001 David A. Schleef <ds@schleef.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, 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. + */ + /* - see http://www.beyondlogic.org/ for information. - or http://www.linux-magazin.de/ausgabe/1999/10/IO/io.html + * Driver: comedi_parport + * Description: Standard PC parallel port + * Author: ds + * Status: works in immediate mode + * Devices: (standard) parallel port [comedi_parport] + * Updated: Tue, 30 Apr 2002 21:11:45 -0700 + * + * A cheap and easy way to get a few more digital I/O lines. Steal + * additional parallel ports from old computers or your neighbors' + * computers. + * + * Option list: + * 0: I/O port base for the parallel port. + * 1: IRQ (optional) + * + * Parallel Port Lines: + * + * pin subdev chan type name + * ----- ------ ---- ---- -------------- + * 1 2 0 DO strobe + * 2 0 0 DIO data 0 + * 3 0 1 DIO data 1 + * 4 0 2 DIO data 2 + * 5 0 3 DIO data 3 + * 6 0 4 DIO data 4 + * 7 0 5 DIO data 5 + * 8 0 6 DIO data 6 + * 9 0 7 DIO data 7 + * 10 1 3 DI ack + * 11 1 4 DI busy + * 12 1 2 DI paper out + * 13 1 1 DI select in + * 14 2 1 DO auto LF + * 15 1 0 DI error + * 16 2 2 DO init + * 17 2 3 DO select printer + * 18-25 ground + * + * When an IRQ is configured subdevice 3 pretends to be a digital + * input subdevice, but it always returns 0 when read. However, if + * you run a command with scan_begin_src=TRIG_EXT, it uses pin 10 + * as a external trigger, which can be used to wake up tasks. */ #include <linux/module.h> -#include "../comedidev.h" #include <linux/interrupt.h> -#include "comedi_fc.h" - -#define PARPORT_SIZE 3 - -#define PARPORT_A 0 -#define PARPORT_B 1 -#define PARPORT_C 2 +#include "../comedidev.h" -struct parport_private { - unsigned int a_data; - unsigned int c_data; - int enable_irq; -}; +#include "comedi_fc.h" -static int parport_insn_a(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +/* + * Register map + */ +#define PARPORT_DATA_REG 0x00 +#define PARPORT_STATUS_REG 0x01 +#define PARPORT_CTRL_REG 0x02 +#define PARPORT_CTRL_IRQ_ENA (1 << 4) +#define PARPORT_CTRL_BIDIR_ENA (1 << 5) + +static int parport_data_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct parport_private *devpriv = dev->private; - - if (data[0]) { - devpriv->a_data &= ~data[0]; - devpriv->a_data |= (data[0] & data[1]); - - outb(devpriv->a_data, dev->iobase + PARPORT_A); - } + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + PARPORT_DATA_REG); - data[1] = inb(dev->iobase + PARPORT_A); + data[1] = inb(dev->iobase + PARPORT_DATA_REG); return insn->n; } -static int parport_insn_config_a(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_data_reg_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct parport_private *devpriv = dev->private; - - if (data[0]) { - s->io_bits = 0xff; - devpriv->c_data &= ~(1 << 5); - } else { - s->io_bits = 0; - devpriv->c_data |= (1 << 5); - } - outb(devpriv->c_data, dev->iobase + PARPORT_C); + unsigned int ctrl; + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0xff); + if (ret) + return ret; + + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + if (s->io_bits) + ctrl &= ~PARPORT_CTRL_BIDIR_ENA; + else + ctrl |= PARPORT_CTRL_BIDIR_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); - return 1; + return insn->n; } -static int parport_insn_b(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_status_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - /* should writes be ignored? */ - /* anyone??? */ - } - - data[1] = (inb(dev->iobase + PARPORT_B) >> 3); + data[1] = inb(dev->iobase + PARPORT_STATUS_REG) >> 3; return insn->n; } -static int parport_insn_c(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_ctrl_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct parport_private *devpriv = dev->private; - - data[0] &= 0x0f; - if (data[0]) { - devpriv->c_data &= ~data[0]; - devpriv->c_data |= (data[0] & data[1]); + unsigned int ctrl; - outb(devpriv->c_data, dev->iobase + PARPORT_C); + if (comedi_dio_update_state(s, data)) { + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl &= (PARPORT_CTRL_IRQ_ENA | PARPORT_CTRL_BIDIR_ENA); + ctrl |= s->state; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); } - data[1] = devpriv->c_data & 0xf; + data[1] = s->state; return insn->n; } -static int parport_intr_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_intr_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { data[1] = 0; return insn->n; @@ -213,12 +198,11 @@ static int parport_intr_cmdtest(struct comedi_device *dev, static int parport_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct parport_private *devpriv = dev->private; + unsigned int ctrl; - devpriv->c_data |= 0x10; - outb(devpriv->c_data, dev->iobase + PARPORT_C); - - devpriv->enable_irq = 1; + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl |= PARPORT_CTRL_IRQ_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); return 0; } @@ -226,12 +210,11 @@ static int parport_intr_cmd(struct comedi_device *dev, static int parport_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct parport_private *devpriv = dev->private; - - devpriv->c_data &= ~0x10; - outb(devpriv->c_data, dev->iobase + PARPORT_C); + unsigned int ctrl; - devpriv->enable_irq = 0; + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl &= ~PARPORT_CTRL_IRQ_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); return 0; } @@ -239,10 +222,11 @@ static int parport_intr_cancel(struct comedi_device *dev, static irqreturn_t parport_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct parport_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[3]; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int ctrl; - if (!devpriv->enable_irq) + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + if (!(ctrl & PARPORT_CTRL_IRQ_ENA)) return IRQ_NONE; comedi_buf_put(s->async, 0); @@ -255,79 +239,69 @@ static irqreturn_t parport_interrupt(int irq, void *d) static int parport_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct parport_private *devpriv; struct comedi_subdevice *s; - unsigned int irq; int ret; - ret = comedi_request_region(dev, it->options[0], PARPORT_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x03); if (ret) return ret; - irq = it->options[1]; - if (irq) { - ret = request_irq(irq, parport_interrupt, 0, dev->board_name, - dev); - if (ret < 0) { - dev_err(dev->class_dev, "irq not available\n"); - return -EINVAL; - } - dev->irq = irq; + if (it->options[1]) { + ret = request_irq(it->options[1], parport_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - ret = comedi_alloc_subdevices(dev, 4); + ret = comedi_alloc_subdevices(dev, dev->irq ? 4 : 3); if (ret) return ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - + /* Digial I/O subdevice - Parallel port DATA register */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_insn_a; - s->insn_config = parport_insn_config_a; - + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_data_reg_insn_bits; + s->insn_config = parport_data_reg_insn_config; + + /* Digial Input subdevice - Parallel port STATUS register */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 5; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_insn_b; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 5; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_status_reg_insn_bits; + + /* Digial Output subdevice - Parallel port CONTROL register */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_insn_c; - - s = &dev->subdevices[3]; - if (irq) { + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_ctrl_reg_insn_bits; + + if (dev->irq) { + /* Digial Input subdevice - Interrupt support */ + s = &dev->subdevices[3]; dev->read_subdev = s; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = 1; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_intr_insn; - s->do_cmdtest = parport_intr_cmdtest; - s->do_cmd = parport_intr_cmd; - s->cancel = parport_intr_cancel; - } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_intr_insn_bits; + s->do_cmdtest = parport_intr_cmdtest; + s->do_cmd = parport_intr_cmd; + s->cancel = parport_intr_cancel; } - devpriv->a_data = 0; - outb(devpriv->a_data, dev->iobase + PARPORT_A); - devpriv->c_data = 0; - outb(devpriv->c_data, dev->iobase + PARPORT_C); + outb(0, dev->iobase + PARPORT_DATA_REG); + outb(0, dev->iobase + PARPORT_CTRL_REG); return 0; } @@ -341,5 +315,5 @@ static struct comedi_driver parport_driver = { module_comedi_driver(parport_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi: Standard parallel port driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index e781716bf355..89836c0828d9 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -40,17 +40,11 @@ Configuration Options: not applicable, uses comedi PCI auto config static int contec_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PIO1616L_DO_REG); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index 5f669709501f..15dd33e3e1c7 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -279,27 +279,23 @@ static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08_do_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct das08_private_struct *devpriv = dev->private; - int wbits; - - /* get current settings of digital output lines */ - wbits = (devpriv->do_mux_bits >> 4) & 0xf; - /* null bits we are going to set */ - wbits &= ~data[0]; - /* set new bit values */ - wbits |= data[0] & data[1]; - /* remember digital output bits */ - /* prevent race with setting of analog input mux */ - spin_lock(&dev->spinlock); - devpriv->do_mux_bits &= ~DAS08_DO_MASK; - devpriv->do_mux_bits |= DAS08_OP(wbits); - outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); - spin_unlock(&dev->spinlock); - data[1] = wbits; + if (comedi_dio_update_state(s, data)) { + /* prevent race with setting of analog input mux */ + spin_lock(&dev->spinlock); + devpriv->do_mux_bits &= ~DAS08_DO_MASK; + devpriv->do_mux_bits |= DAS08_OP(s->state); + outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); + spin_unlock(&dev->spinlock); + } + + data[1] = s->state; return insn->n; } @@ -316,17 +312,13 @@ static int das08jr_di_rbits(struct comedi_device *dev, static int das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct das08_private_struct *devpriv = dev->private; - - /* null bits we are going to set */ - devpriv->do_bits &= ~data[0]; - /* set new bit values */ - devpriv->do_bits |= data[0] & data[1]; - outb(devpriv->do_bits, dev->iobase + DAS08JR_DIO); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS08JR_DIO); - data[1] = devpriv->do_bits; + data[1] = s->state; return insn->n; } diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index cce1b584200a..46a314c5113e 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -41,7 +41,6 @@ struct das08_board_struct { struct das08_private_struct { unsigned int do_mux_bits; /* bits for do/mux register on boards without separate do register */ - unsigned int do_bits; /* bits for do register on boards with register dedicated to digital out only */ const unsigned int *pg_gainlist; unsigned int ao_readback[2]; /* assume 2 AO channels */ }; diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 1b0793f33b9f..a8446ca04110 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -675,21 +675,19 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->scan_begin_src == TRIG_TIMER) { unsigned int tmp = cmd->scan_begin_arg; /* set divisors, correct timing arguments */ - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->scan_begin_arg, cmd->flags); err += (tmp != cmd->scan_begin_arg); } if (cmd->convert_src == TRIG_TIMER) { unsigned int tmp = cmd->convert_arg; /* set divisors, correct timing arguments */ - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->convert_arg, cmd->flags); err += (tmp != cmd->convert_arg); } if (err) @@ -725,11 +723,9 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, struct das16_private_struct *devpriv = dev->private; unsigned long timer_base = dev->iobase + DAS16_TIMER_BASE_REG; - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, - &devpriv->divisor1, - &devpriv->divisor2, - &ns, - rounding_flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, &devpriv->divisor2, + &ns, rounding_flags); /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ i8254_load(timer_base, 0, 1, devpriv->divisor1, 2); @@ -850,7 +846,7 @@ static void das16_ai_munge(struct comedi_device *dev, unsigned int start_chan_index) { unsigned int i, num_samples = num_bytes / sizeof(short); - short *data = array; + unsigned short *data = array; for (i = 0; i < num_samples; i++) { data[i] = le16_to_cpu(data[i]); @@ -952,15 +948,8 @@ static int das16_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outb(s->state, dev->iobase + DAS16_DIO_REG); - } data[1] = s->state; @@ -1043,14 +1032,15 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) status = inb(dev->iobase + DAS1600_STATUS_REG); if (status & DAS1600_STATUS_CLK_10MHZ) - devpriv->clockbase = 100; + devpriv->clockbase = I8254_OSC_BASE_10MHZ; else - devpriv->clockbase = 1000; + devpriv->clockbase = I8254_OSC_BASE_1MHZ; } else { if (it->options[3]) - devpriv->clockbase = 1000 / it->options[3]; + devpriv->clockbase = I8254_OSC_BASE_1MHZ / + it->options[3]; else - devpriv->clockbase = 1000; /* 1 MHz default */ + devpriv->clockbase = I8254_OSC_BASE_1MHZ; } /* initialize dma */ diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index b943c449b691..fce9acfe8084 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -63,8 +63,6 @@ irq can be omitted, although the cmd interface will not work without it. #define DAS16M1_SIZE 16 #define DAS16M1_SIZE2 8 -#define DAS16M1_XTAL 100 /* 10 MHz master clock */ - #define FIFO_SIZE 1024 /* 1024 sample fifo */ /* @@ -133,19 +131,18 @@ struct das16m1_private_struct { * needed to keep track of whether new count has been loaded into * counter yet (loaded by first sample conversion) */ u16 initial_hw_count; - short ai_buffer[FIFO_SIZE]; - unsigned int do_bits; /* saves status of digital output bits */ + unsigned short ai_buffer[FIFO_SIZE]; unsigned int divisor1; /* divides master clock to obtain conversion speed */ unsigned int divisor2; /* divides master clock to obtain conversion speed */ unsigned long extra_iobase; }; -static inline short munge_sample(short data) +static inline unsigned short munge_sample(unsigned short data) { return (data >> 4) & 0xfff; } -static void munge_sample_array(short *array, unsigned int num_elements) +static void munge_sample_array(unsigned short *array, unsigned int num_elements) { unsigned int i; @@ -208,11 +205,10 @@ static int das16m1_cmd_test(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->convert_arg, cmd->flags); if (tmp != cmd->convert_arg) err++; } @@ -251,9 +247,10 @@ static unsigned int das16m1_set_pacer(struct comedi_device *dev, { struct das16m1_private_struct *devpriv = dev->private; - i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1), - &(devpriv->divisor2), &ns, - rounding_flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer_2div(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &ns, rounding_flags); /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1, @@ -393,22 +390,13 @@ static int das16m1_di_rbits(struct comedi_device *dev, static int das16m1_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct das16m1_private_struct *devpriv = dev->private; - unsigned int wbits; - - /* only set bits that have been masked */ - data[0] &= 0xf; - wbits = devpriv->do_bits; - /* zero bits that have been masked */ - wbits &= ~data[0]; - /* set masked bits */ - wbits |= data[0] & data[1]; - devpriv->do_bits = wbits; - data[1] = wbits; + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS16M1_DIO); - outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); + data[1] = s->state; return insn->n; } @@ -649,7 +637,7 @@ static int das16m1_attach(struct comedi_device *dev, outb(TOTAL_CLEAR, dev->iobase + DAS16M1_8254_FIRST_CNTRL); /* initialize digital output lines */ - outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); + outb(0, dev->iobase + DAS16M1_DIO); /* set the interrupt level */ if (dev->irq) diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 5b300294d322..1880038956d0 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -108,7 +108,6 @@ TODO: /* misc. defines */ #define DAS1800_SIZE 16 /* uses 16 io addresses */ #define FIFO_SIZE 1024 /* 1024 sample fifo */ -#define TIMER_BASE 200 /* 5 Mhz master clock */ #define UNIPOLAR 0x4 /* bit that determines whether input range is uni/bipolar */ #define DMA_BUF_SIZE 0x1ff00 /* size in bytes of dma buffers */ @@ -427,7 +426,6 @@ struct das1800_private { volatile unsigned int count; /* number of data points left to be taken */ unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */ unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */ - int do_bits; /* digital output bits */ int irq_dma_bits; /* bits for control register b */ /* dma bits for control register b, stored so that dma can be * turned on and off */ @@ -440,7 +438,8 @@ struct das1800_private { uint16_t *dma_current_buf; /* pointer to dma buffer currently being used */ unsigned int dma_transfer_size; /* size of transfer currently used, in bytes */ unsigned long iobase2; /* secondary io address used for analog out on 'ao' boards */ - short ao_update_bits; /* remembers the last write to the 'update' dac */ + unsigned short ao_update_bits; /* remembers the last write to the + * 'update' dac */ }; /* analog out range for 'ao' boards */ @@ -503,7 +502,7 @@ static void das1800_handle_fifo_not_empty(struct comedi_device *dev, struct comedi_subdevice *s) { struct das1800_private *devpriv = dev->private; - short dpnt; + unsigned short dpnt; int unipolar; struct comedi_cmd *cmd = &s->async->cmd; @@ -840,12 +839,11 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_FOLLOW) { tmp_arg = cmd->convert_arg; /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd-> - flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->convert_arg, + cmd->flags); if (tmp_arg != cmd->convert_arg) err++; } @@ -870,16 +868,11 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, } tmp_arg = cmd->scan_begin_arg; /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv-> - divisor1), - &(devpriv-> - divisor2), - &(cmd-> - scan_begin_arg), - cmd-> - flags & - TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->scan_begin_arg, + cmd->flags); if (tmp_arg != cmd->scan_begin_arg) err++; } @@ -1011,12 +1004,10 @@ static int setup_counters(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { /* set conversion frequency */ period = cmd->convert_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &devpriv->divisor1, - &devpriv->divisor2, - &period, - cmd->flags & - TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &period, cmd->flags); if (das1800_set_frequency(dev) < 0) return -1; } @@ -1024,9 +1015,10 @@ static int setup_counters(struct comedi_device *dev, case TRIG_TIMER: /* in burst mode */ /* set scan frequency */ period = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &devpriv->divisor1, - &devpriv->divisor2, &period, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &period, cmd->flags); if (das1800_set_frequency(dev) < 0) return -1; break; @@ -1220,7 +1212,7 @@ static int das1800_ai_rinsn(struct comedi_device *dev, int i, n; int chan, range, aref, chan_range; int timeout = 1000; - short dpnt; + unsigned short dpnt; int conv_flags = 0; unsigned long irq_flags; @@ -1285,7 +1277,7 @@ static int das1800_ao_winsn(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); /* int range = CR_RANGE(insn->chanspec); */ int update_chan = thisboard->ao_n_chan - 1; - short output; + unsigned short output; unsigned long irq_flags; /* card expects two's complement data */ @@ -1319,24 +1311,15 @@ static int das1800_di_rbits(struct comedi_device *dev, return insn->n; } -/* writes to digital output channels */ static int das1800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct das1800_private *devpriv = dev->private; - unsigned int wbits; - - /* only set bits that have been masked */ - data[0] &= (1 << s->n_chan) - 1; - wbits = devpriv->do_bits; - wbits &= ~data[0]; - wbits |= data[0] & data[1]; - devpriv->do_bits = wbits; - - outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS1800_DIGITAL); - data[1] = devpriv->do_bits; + data[1] = s->state; return insn->n; } @@ -1644,7 +1627,7 @@ static int das1800_attach(struct comedi_device *dev, das1800_cancel(dev, dev->read_subdev); /* initialize digital out channels */ - outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL); + outb(0, dev->iobase + DAS1800_DIGITAL); /* initialize analog out channels */ if (thisboard->ao_ability == 1) { diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 11e16114e4e3..5af0a5764a8c 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -66,7 +66,6 @@ cmd triggers supported: #include "comedi_fc.h" #define DAS800_SIZE 8 -#define TIMER_BASE 1000 #define N_CHAN_AI 8 /* number of analog input channels */ /* Registers for the das800 */ @@ -356,11 +355,10 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, int tmp = cmd->convert_arg; /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_1MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->convert_arg, cmd->flags); if (tmp != cmd->convert_arg) err++; } @@ -630,13 +628,9 @@ static int das800_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct das800_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; unsigned long irq_flags; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) { devpriv->do_bits = s->state << 4; spin_lock_irqsave(&dev->spinlock, irq_flags); diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 118a4fd129f9..b04a5633f754 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -596,52 +596,40 @@ static int dmm32at_ao_rinsn(struct comedi_device *dev, static int dmm32at_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct dmm32at_private *devpriv = dev->private; - unsigned char diobits; - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - /* outw(s->state,dev->iobase + DMM32AT_DIO); */ + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + /* get access to the DIO regs */ + outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); + + /* if either part of dio is set for output */ + if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) || + ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) { + val = (s->state & 0x00ff0000) >> 16; + outb(val, dev->iobase + DMM32AT_DIOC); + } + if ((devpriv->dio_config & DMM32AT_DIRB) == 0) { + val = (s->state & 0x0000ff00) >> 8; + outb(val, dev->iobase + DMM32AT_DIOB); + } + if ((devpriv->dio_config & DMM32AT_DIRA) == 0) { + val = (s->state & 0x000000ff); + outb(val, dev->iobase + DMM32AT_DIOA); + } } - /* get access to the DIO regs */ - outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); - - /* if either part of dio is set for output */ - if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) || - ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) { - diobits = (s->state & 0x00ff0000) >> 16; - outb(diobits, dev->iobase + DMM32AT_DIOC); - } - if ((devpriv->dio_config & DMM32AT_DIRB) == 0) { - diobits = (s->state & 0x0000ff00) >> 8; - outb(diobits, dev->iobase + DMM32AT_DIOB); - } - if ((devpriv->dio_config & DMM32AT_DIRA) == 0) { - diobits = (s->state & 0x000000ff); - outb(diobits, dev->iobase + DMM32AT_DIOA); - } + val = inb(dev->iobase + DMM32AT_DIOA); + val |= inb(dev->iobase + DMM32AT_DIOB) << 8; + val |= inb(dev->iobase + DMM32AT_DIOC) << 16; + s->state = val; - /* now read the state back in */ - s->state = inb(dev->iobase + DMM32AT_DIOC); - s->state <<= 8; - s->state |= inb(dev->iobase + DMM32AT_DIOB); - s->state <<= 8; - s->state |= inb(dev->iobase + DMM32AT_DIOA); - data[1] = s->state; - - /* on return, data[1] contains the value of the digital - * input and output lines. */ - /* data[1]=inw(dev->iobase + DMM32AT_DIO); */ - /* or we could just return the software copy of the output values if - * it was a purely digital output subdevice */ - /* data[1]=s->state; */ + data[1] = val; return insn->n; } diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index 38918a1198aa..811c8c59c017 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -260,7 +260,8 @@ static int dt2801_readdata(struct comedi_device *dev, int *data) static int dt2801_readdata2(struct comedi_device *dev, int *data) { - int lb, hb; + int lb = 0; + int hb = 0; int ret; ret = dt2801_readdata(dev, &lb); @@ -528,23 +529,23 @@ static int dt2801_ao_insn_write(struct comedi_device *dev, static int dt2801_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int which = 0; - - if (s == &dev->subdevices[3]) - which = 1; + int which = (s == &dev->subdevices[3]) ? 1 : 0; + unsigned int val = 0; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { dt2801_writecmd(dev, DT_C_WRITE_DIG); dt2801_writedata(dev, which); dt2801_writedata(dev, s->state); } + dt2801_writecmd(dev, DT_C_READ_DIG); dt2801_writedata(dev, which); - dt2801_readdata(dev, data + 1); + dt2801_readdata(dev, &val); + + data[1] = val; return insn->n; } diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index a41a5716f358..0ca02fa7ba1b 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -353,11 +353,11 @@ static int dt2811_di_insn_bits(struct comedi_device *dev, static int dt2811_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outb(s->state, dev->iobase + DT2811_DIO); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DT2811_DIO); data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c index f4a8529239b5..bf589936e546 100644 --- a/drivers/staging/comedi/drivers/dt2817.c +++ b/drivers/staging/comedi/drivers/dt2817.c @@ -80,36 +80,31 @@ static int dt2817_dio_insn_config(struct comedi_device *dev, static int dt2817_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int changed; - - /* It's questionable whether it is more important in - * a driver like this to be deterministic or fast. - * We choose fast. */ - - if (data[0]) { - changed = s->state; - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - changed ^= s->state; - changed &= s->io_bits; - if (changed & 0x000000ff) - outb(s->state & 0xff, dev->iobase + DT2817_DATA + 0); - if (changed & 0x0000ff00) - outb((s->state >> 8) & 0xff, - dev->iobase + DT2817_DATA + 1); - if (changed & 0x00ff0000) - outb((s->state >> 16) & 0xff, - dev->iobase + DT2817_DATA + 2); - if (changed & 0xff000000) - outb((s->state >> 24) & 0xff, - dev->iobase + DT2817_DATA + 3); + unsigned long iobase = dev->iobase + DT2817_DATA; + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x000000ff) + outb(s->state & 0xff, iobase + 0); + if (mask & 0x0000ff00) + outb((s->state >> 8) & 0xff, iobase + 1); + if (mask & 0x00ff0000) + outb((s->state >> 16) & 0xff, iobase + 2); + if (mask & 0xff000000) + outb((s->state >> 24) & 0xff, iobase + 3); } - data[1] = inb(dev->iobase + DT2817_DATA + 0); - data[1] |= (inb(dev->iobase + DT2817_DATA + 1) << 8); - data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16); - data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24); + + val = inb(iobase + 0); + val |= (inb(iobase + 1) << 8); + val |= (inb(iobase + 2) << 16); + val |= (inb(iobase + 3) << 24); + + data[1] = val; return insn->n; } diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index da3ee859bdbc..a01e6b553887 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -226,7 +226,7 @@ struct dt282x_private { const struct comedi_lrange *darangelist[2]; - short ao[2]; + unsigned short ao[2]; volatile int dacsr; /* software copies of registers */ volatile int adcsr; @@ -237,7 +237,7 @@ struct dt282x_private { struct { int chan; - short *buf; /* DMA buffer */ + unsigned short *buf; /* DMA buffer */ volatile int size; /* size of current transfer */ } dma[2]; int dma_maxsize; /* max size of DMA transfer (in bytes) */ @@ -283,7 +283,7 @@ static void dt282x_disable_dma(struct comedi_device *dev); static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2); -static void dt282x_munge(struct comedi_device *dev, short *buf, +static void dt282x_munge(struct comedi_device *dev, unsigned short *buf, unsigned int nbytes) { const struct dt282x_board *board = comedi_board(dev); @@ -496,9 +496,9 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) #if 0 if (adcsr & DT2821_ADDONE) { int ret; - short data; + unsigned short data; - data = (short)inw(dev->iobase + DT2821_ADDAT); + data = inw(dev->iobase + DT2821_ADDAT); data &= (1 << board->adbits) - 1; if (devpriv->ad_2scomp) @@ -796,7 +796,7 @@ static int dt282x_ao_insn_write(struct comedi_device *dev, { const struct dt282x_board *board = comedi_board(dev); struct dt282x_private *devpriv = dev->private; - short d; + unsigned short d; unsigned int chan; chan = CR_CHAN(insn->chanspec); @@ -967,14 +967,12 @@ static int dt282x_ao_cancel(struct comedi_device *dev, static int dt282x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + DT2821_DIODAT); - } + data[1] = inw(dev->iobase + DT2821_DIODAT); return insn->n; diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 64ef87598b60..292226eeff92 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -331,7 +331,7 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev, int rear; int count; int i; - short data; + unsigned short data; front = readw(devpriv->io_addr + DPR_AD_Buf_Front); count = front - devpriv->ai_front; @@ -665,13 +665,12 @@ static int dt3k_dio_insn_config(struct comedi_device *dev, static int dt3k_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[1] & data[0]; + if (comedi_dio_update_state(s, data)) dt3k_writesingle(dev, SUBS_DOUT, 0, s->state); - } + data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0); return insn->n; diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index b5e6f33dc217..73af600c1725 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -85,13 +85,9 @@ for my needs. #define F020_MASK_DACxCN_DACxEN 0x80 enum { - /* A/D D/A DI DO CT */ - DT9812_DEVID_DT9812_10, /* 8 2 8 8 1 +/- 10V */ - DT9812_DEVID_DT9812_2PT5, /* 8 2 8 8 1 0-2.44V */ -#if 0 - DT9812_DEVID_DT9813, /* 16 2 4 4 1 +/- 10V */ - DT9812_DEVID_DT9814 /* 24 2 0 0 1 +/- 10V */ -#endif + /* A/D D/A DI DO CT */ + DT9812_DEVID_DT9812_10, /* 8 2 8 8 1 +/- 10V */ + DT9812_DEVID_DT9812_2PT5, /* 8 2 8 8 1 0-2.44V */ }; enum dt9812_gain { @@ -580,15 +576,8 @@ static int dt9812_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) dt9812_digital_out(dev, s->state); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index fd525f499f2a..f2a9f1c2f3b6 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -147,33 +147,23 @@ static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev, return insn->n; } -/* digital output bit interface */ static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct dyna_pci10xx_private *devpriv = dev->private; - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. - * s->state contains the previous write data - */ mutex_lock(&devpriv->mutex); - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { smp_mb(); outw_p(s->state, devpriv->BADR3); udelay(10); } - /* - * On return, data[1] contains the value of the digital - * input and output lines. We just return the software copy of the - * output values if it was a purely digital output subdevice. - */ data[1] = s->state; mutex_unlock(&devpriv->mutex); + return insn->n; } diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index 8d70f64b1574..e3ff4c438979 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -25,8 +25,7 @@ Configuration options: #define FL512_SIZE 16 /* the size of the used memory */ struct fl512_private { - - short ao_readback[2]; + unsigned short ao_readback[2]; }; static const struct comedi_lrange range_fl512 = { 4, { diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 3889d23292d0..1e16641ec52d 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -118,9 +118,7 @@ struct icp_multi_private { unsigned char act_chanlist_len; /* len of scanlist */ unsigned char act_chanlist_pos; /* actual position in MUX list */ unsigned int *ai_chanlist; /* actaul chanlist */ - short *ai_data; /* data buffer */ - short ao_data[4]; /* data output buffer */ - short di_data; /* Digital input data */ + unsigned short ao_data[4]; /* data output buffer */ unsigned int do_data; /* Remember digital output data */ }; @@ -348,18 +346,13 @@ static int icp_multi_insn_bits_di(struct comedi_device *dev, static int icp_multi_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - printk(KERN_DEBUG "Digital outputs = %4x \n", s->state); - + if (comedi_dio_update_state(s, data)) writew(s->state, devpriv->io_addr + ICP_MULTI_DO); - } data[1] = readw(devpriv->io_addr + ICP_MULTI_DI); @@ -548,7 +541,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = 16; s->range_table = &range_digital; - s->io_bits = 0; s->insn_bits = icp_multi_insn_bits_di; s = &dev->subdevices[3]; @@ -558,8 +550,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->len_chanlist = 8; s->range_table = &range_digital; - s->io_bits = 0xff; - s->state = 0; s->insn_bits = icp_multi_insn_bits_do; s = &dev->subdevices[4]; diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 5c3a318b4640..8577778441fa 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -378,13 +378,10 @@ static int ii20k_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { struct ii20k_private *devpriv = dev->private; - unsigned int mask = data[0] & s->io_bits; /* outputs only */ - unsigned int bits = data[1]; + unsigned int mask; + mask = comedi_dio_update_state(s, data); if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - if (mask & 0x000000ff) writeb((s->state >> 0) & 0xff, devpriv->ioaddr + II20K_DIO0_REG); diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 8f4afadab76a..3d12e9135926 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -427,7 +427,7 @@ static int xilinx_download(struct comedi_device *dev) static void me4000_reset(struct comedi_device *dev) { struct me4000_info *info = dev->private; - unsigned long val; + unsigned int val; int chan; /* Make a hardware reset */ @@ -480,9 +480,9 @@ static int me4000_ai_insn_read(struct comedi_device *dev, int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); - unsigned long entry = 0; - unsigned long tmp; - long lval; + unsigned int entry = 0; + unsigned int tmp; + unsigned int lval; if (insn->n == 0) { return 0; @@ -586,7 +586,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, static int me4000_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned long tmp; + unsigned int tmp; /* Stop any running conversion */ tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); @@ -783,7 +783,7 @@ static int ai_prepare(struct comedi_device *dev, unsigned int scan_ticks, unsigned int chan_ticks) { - unsigned long tmp = 0; + unsigned int tmp = 0; /* Write timer arguments */ ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks); @@ -1108,7 +1108,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) struct comedi_subdevice *s = &dev->subdevices[0]; int i; int c = 0; - long lval; + unsigned int lval; if (!dev->attached) return IRQ_NONE; @@ -1252,7 +1252,7 @@ static int me4000_ao_insn_write(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); - unsigned long tmp; + unsigned int tmp; if (insn->n == 0) { return 0; @@ -1313,29 +1313,12 @@ static int me4000_ao_insn_read(struct comedi_device *dev, return 1; } -/*============================================================================= - Digital I/O section - ===========================================================================*/ - static int me4000_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* - * The insn data consists of a mask in data[0] and the new data - * in data[1]. The mask defines which bits we are concerning about. - * The new data must be anded with the mask. - * Each channel corresponds to a bit. - */ - if (data[0]) { - /* Check if requested ports are configured for output */ - if ((s->io_bits & data[0]) != data[0]) - return -EIO; - - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - - /* Write out the new digital output lines */ + if (comedi_dio_update_state(s, data)) { outl((s->state >> 0) & 0xFF, dev->iobase + ME4000_DIO_PORT_0_REG); outl((s->state >> 8) & 0xFF, @@ -1346,8 +1329,6 @@ static int me4000_dio_insn_bits(struct comedi_device *dev, dev->iobase + ME4000_DIO_PORT_3_REG); } - /* On return, data[1] contains the value of - the digital input and output lines. */ data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) | ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) | ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) | diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index a6f6d4a46587..24ec9ef9b1a0 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -222,15 +222,11 @@ static int me_dio_insn_bits(struct comedi_device *dev, struct me_private_data *dev_private = dev->private; void __iomem *mmio_porta = dev_private->me_regbase + ME_DIO_PORT_A; void __iomem *mmio_portb = dev_private->me_regbase + ME_DIO_PORT_B; - unsigned int mask = data[0]; - unsigned int bits = data[1]; + unsigned int mask; unsigned int val; - mask &= s->io_bits; /* only update the COMEDI_OUTPUT channels */ + mask = comedi_dio_update_state(s, data); if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - if (mask & 0x0000ffff) writew((s->state & 0xffff), mmio_porta); if (mask & 0xffff0000) @@ -545,7 +541,6 @@ static int me_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = me_dio_insn_bits; s->insn_config = me_dio_insn_config; - s->io_bits = 0; dev_info(dev->class_dev, "%s: %s attached\n", dev->driver->driver_name, dev->board_name); diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index 9d75ea4e201b..3ca755eca285 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -163,11 +163,11 @@ static int multiq3_di_insn_bits(struct comedi_device *dev, static int multiq3_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - outw(s->state, dev->iobase + MULTIQ3_DIGOUT_PORT); + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + MULTIQ3_DIGOUT_PORT); data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index c2745f201f2c..85aa9609d6a2 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -1,41 +1,33 @@ /* - comedi/drivers/ni_6527.c - driver for National Instruments PCI-6527 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.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, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: ni_6527 -Description: National Instruments 6527 -Author: ds -Status: works -Devices: [National Instruments] PCI-6527 (ni6527), PXI-6527 -Updated: Sat, 25 Jan 2003 13:24:40 -0800 - - -*/ + * ni_6527.c + * Comedi driver for National Instruments PCI-6527 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.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, 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. + */ /* - Manuals (available from ftp://ftp.natinst.com/support/manuals) - - 370106b.pdf 6527 Register Level Programmer Manual - + * Driver: ni_6527 + * Description: National Instruments 6527 + * Devices: (National Instruments) PCI-6527 [pci-6527] + * (National Instruments) PXI-6527 [pxi-6527] + * Author: David A. Schleef <ds@schleef.org> + * Updated: Sat, 25 Jan 2003 13:24:40 -0800 + * Status: works + * + * Configuration Options: not applicable, uses PCI auto config */ -#define DEBUG 1 -#define DEBUG_FLAGS - #include <linux/module.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -43,39 +35,41 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800 #include "../comedidev.h" #include "comedi_fc.h" -#include "mite.h" - -#define DRIVER_NAME "ni_6527" - -#define NI6527_DIO_SIZE 4096 -#define NI6527_MITE_SIZE 4096 - -#define Port_Register(x) (0x00+(x)) -#define ID_Register 0x06 - -#define Clear_Register 0x07 -#define ClrEdge 0x08 -#define ClrOverflow 0x04 -#define ClrFilter 0x02 -#define ClrInterval 0x01 -#define Filter_Interval(x) (0x08+(x)) -#define Filter_Enable(x) (0x0c+(x)) - -#define Change_Status 0x14 -#define MasterInterruptStatus 0x04 -#define Overflow 0x02 -#define EdgeStatus 0x01 - -#define Master_Interrupt_Control 0x15 -#define FallingEdgeIntEnable 0x10 -#define RisingEdgeIntEnable 0x08 -#define MasterInterruptEnable 0x04 -#define OverflowIntEnable 0x02 -#define EdgeIntEnable 0x01 - -#define Rising_Edge_Detection_Enable(x) (0x018+(x)) -#define Falling_Edge_Detection_Enable(x) (0x020+(x)) +/* + * PCI BAR1 - Register memory map + * + * Manuals (available from ftp://ftp.natinst.com/support/manuals) + * 370106b.pdf 6527 Register Level Programmer Manual + */ +#define NI6527_DI_REG(x) (0x00 + (x)) +#define NI6527_DO_REG(x) (0x03 + (x)) +#define NI6527_ID_REG 0x06 +#define NI6527_CLR_REG 0x07 +#define NI6527_CLR_EDGE (1 << 3) +#define NI6527_CLR_OVERFLOW (1 << 2) +#define NI6527_CLR_FILT (1 << 1) +#define NI6527_CLR_INTERVAL (1 << 0) +#define NI6527_CLR_IRQS (NI6527_CLR_EDGE | NI6527_CLR_OVERFLOW) +#define NI6527_CLR_RESET_FILT (NI6527_CLR_FILT | NI6527_CLR_INTERVAL) +#define NI6527_FILT_INTERVAL_REG(x) (0x08 + (x)) +#define NI6527_FILT_ENA_REG(x) (0x0c + (x)) +#define NI6527_STATUS_REG 0x14 +#define NI6527_STATUS_IRQ (1 << 2) +#define NI6527_STATUS_OVERFLOW (1 << 1) +#define NI6527_STATUS_EDGE (1 << 0) +#define NI6527_CTRL_REG 0x15 +#define NI6527_CTRL_FALLING (1 << 4) +#define NI6527_CTRL_RISING (1 << 3) +#define NI6527_CTRL_IRQ (1 << 2) +#define NI6527_CTRL_OVERFLOW (1 << 1) +#define NI6527_CTRL_EDGE (1 << 0) +#define NI6527_CTRL_DISABLE_IRQS 0 +#define NI6527_CTRL_ENABLE_IRQS (NI6527_CTRL_FALLING | \ + NI6527_CTRL_RISING | \ + NI6527_CTRL_IRQ | NI6527_CTRL_EDGE) +#define NI6527_RISING_EDGE_REG(x) (0x18 + (x)) +#define NI6527_FALLING_EDGE_REG(x) (0x20 + (x)) enum ni6527_boardid { BOARD_PCI6527, @@ -96,96 +90,113 @@ static const struct ni6527_board ni6527_boards[] = { }; struct ni6527_private { - struct mite_struct *mite; + void __iomem *mmio_base; unsigned int filter_interval; unsigned int filter_enable; }; +static void ni6527_set_filter_interval(struct comedi_device *dev, + unsigned int val) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + if (val != devpriv->filter_interval) { + writeb(val & 0xff, mmio + NI6527_FILT_INTERVAL_REG(0)); + writeb((val >> 8) & 0xff, mmio + NI6527_FILT_INTERVAL_REG(1)); + writeb((val >> 16) & 0x0f, mmio + NI6527_FILT_INTERVAL_REG(2)); + + writeb(NI6527_CLR_INTERVAL, mmio + NI6527_CLR_REG); + + devpriv->filter_interval = val; + } +} + +static void ni6527_set_filter_enable(struct comedi_device *dev, + unsigned int val) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + writeb(val & 0xff, mmio + NI6527_FILT_ENA_REG(0)); + writeb((val >> 8) & 0xff, mmio + NI6527_FILT_ENA_REG(1)); + writeb((val >> 16) & 0xff, mmio + NI6527_FILT_ENA_REG(2)); +} + static int ni6527_di_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni6527_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int interval; - if (insn->n != 2) - return -EINVAL; - - if (data[0] != INSN_CONFIG_FILTER) - return -EINVAL; - - if (data[1]) { + switch (data[0]) { + case INSN_CONFIG_FILTER: + /* + * The deglitch filter interval is specified in nanoseconds. + * The hardware supports intervals in 200ns increments. Round + * the user values up and return the actual interval. + */ interval = (data[1] + 100) / 200; data[1] = interval * 200; - if (interval != devpriv->filter_interval) { - writeb(interval & 0xff, - devpriv->mite->daq_io_addr + Filter_Interval(0)); - writeb((interval >> 8) & 0xff, - devpriv->mite->daq_io_addr + Filter_Interval(1)); - writeb((interval >> 16) & 0x0f, - devpriv->mite->daq_io_addr + Filter_Interval(2)); - - writeb(ClrInterval, - devpriv->mite->daq_io_addr + Clear_Register); - - devpriv->filter_interval = interval; + if (interval) { + ni6527_set_filter_interval(dev, interval); + devpriv->filter_enable |= 1 << chan; + } else { + devpriv->filter_enable &= ~(1 << chan); } - - devpriv->filter_enable |= 1 << chan; - } else { - devpriv->filter_enable &= ~(1 << chan); + ni6527_set_filter_enable(dev, devpriv->filter_enable); + break; + default: + return -EINVAL; } - writeb(devpriv->filter_enable, - devpriv->mite->daq_io_addr + Filter_Enable(0)); - writeb(devpriv->filter_enable >> 8, - devpriv->mite->daq_io_addr + Filter_Enable(1)); - writeb(devpriv->filter_enable >> 16, - devpriv->mite->daq_io_addr + Filter_Enable(2)); - - return 2; + return insn->n; } static int ni6527_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + unsigned int val; - data[1] = readb(devpriv->mite->daq_io_addr + Port_Register(0)); - data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(1)) << 8; - data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(2)) << 16; + val = readb(mmio + NI6527_DI_REG(0)); + val |= (readb(mmio + NI6527_DI_REG(1)) << 8); + val |= (readb(mmio + NI6527_DI_REG(2)) << 16); + + data[1] = val; return insn->n; } static int ni6527_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni6527_private *devpriv = dev->private; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - /* The open relay state on the board cooresponds to 1, - * but in Comedi, it is represented by 0. */ - if (data[0] & 0x0000ff) { - writeb((s->state ^ 0xff), - devpriv->mite->daq_io_addr + Port_Register(3)); - } - if (data[0] & 0x00ff00) { - writeb((s->state >> 8) ^ 0xff, - devpriv->mite->daq_io_addr + Port_Register(4)); - } - if (data[0] & 0xff0000) { - writeb((s->state >> 16) ^ 0xff, - devpriv->mite->daq_io_addr + Port_Register(5)); - } + void __iomem *mmio = devpriv->mmio_base; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + /* Outputs are inverted */ + unsigned int val = s->state ^ 0xffffff; + + if (mask & 0x0000ff) + writeb(val & 0xff, mmio + NI6527_DO_REG(0)); + if (mask & 0x00ff00) + writeb((val >> 8) & 0xff, mmio + NI6527_DO_REG(1)); + if (mask & 0xff0000) + writeb((val >> 16) & 0xff, mmio + NI6527_DO_REG(2)); } + data[1] = s->state; return insn->n; @@ -195,21 +206,22 @@ static irqreturn_t ni6527_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct ni6527_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[2]; + struct comedi_subdevice *s = dev->read_subdev; + void __iomem *mmio = devpriv->mmio_base; unsigned int status; - status = readb(devpriv->mite->daq_io_addr + Change_Status); - if ((status & MasterInterruptStatus) == 0) - return IRQ_NONE; - if ((status & EdgeStatus) == 0) + status = readb(mmio + NI6527_STATUS_REG); + if (!(status & NI6527_STATUS_IRQ)) return IRQ_NONE; - writeb(ClrEdge | ClrOverflow, - devpriv->mite->daq_io_addr + Clear_Register); + if (status & NI6527_STATUS_EDGE) { + comedi_buf_put(s->async, 0); + s->async->events |= COMEDI_CB_EOS; + comedi_event(dev, s); + } + + writeb(NI6527_CLR_IRQS, mmio + NI6527_CLR_REG); - comedi_buf_put(s->async, 0); - s->async->events |= COMEDI_CB_EOS; - comedi_event(dev, s); return IRQ_HANDLED; } @@ -259,13 +271,10 @@ static int ni6527_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct ni6527_private *devpriv = dev->private; - /* struct comedi_cmd *cmd = &s->async->cmd; */ + void __iomem *mmio = devpriv->mmio_base; - writeb(ClrEdge | ClrOverflow, - devpriv->mite->daq_io_addr + Clear_Register); - writeb(FallingEdgeIntEnable | RisingEdgeIntEnable | - MasterInterruptEnable | EdgeIntEnable, - devpriv->mite->daq_io_addr + Master_Interrupt_Control); + writeb(NI6527_CLR_IRQS, mmio + NI6527_CLR_REG); + writeb(NI6527_CTRL_ENABLE_IRQS, mmio + NI6527_CTRL_REG); return 0; } @@ -274,8 +283,9 @@ static int ni6527_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; - writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); + writeb(NI6527_CTRL_DISABLE_IRQS, mmio + NI6527_CTRL_REG); return 0; } @@ -288,32 +298,54 @@ static int ni6527_intr_insn_bits(struct comedi_device *dev, return insn->n; } +static void ni6527_set_edge_detection(struct comedi_device *dev, + unsigned int rising, + unsigned int falling) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + /* enable rising-edge detection channels */ + writeb(rising & 0xff, mmio + NI6527_RISING_EDGE_REG(0)); + writeb((rising >> 8) & 0xff, mmio + NI6527_RISING_EDGE_REG(1)); + writeb((rising >> 16) & 0xff, mmio + NI6527_RISING_EDGE_REG(2)); + + /* enable falling-edge detection channels */ + writeb(falling & 0xff, mmio + NI6527_FALLING_EDGE_REG(0)); + writeb((falling >> 8) & 0xff, mmio + NI6527_FALLING_EDGE_REG(1)); + writeb((falling >> 16) & 0xff, mmio + NI6527_FALLING_EDGE_REG(2)); +} + static int ni6527_intr_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) +{ + switch (data[0]) { + case INSN_CONFIG_CHANGE_NOTIFY: + /* check_insn_config_length() does not check this instruction */ + if (insn->n != 3) + return -EINVAL; + ni6527_set_edge_detection(dev, data[1], data[2]); + break; + default: + return -EINVAL; + } + + return insn->n; +} + +static void ni6527_reset(struct comedi_device *dev) { struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; - if (insn->n < 1) - return -EINVAL; - if (data[0] != INSN_CONFIG_CHANGE_NOTIFY) - return -EINVAL; + /* disable deglitch filters on all channels */ + ni6527_set_filter_enable(dev, 0); - writeb(data[1], - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0)); - writeb(data[1] >> 8, - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(1)); - writeb(data[1] >> 16, - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(2)); - - writeb(data[2], - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0)); - writeb(data[2] >> 8, - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(1)); - writeb(data[2] >> 16, - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(2)); - - return 2; + writeb(NI6527_CLR_IRQS | NI6527_CLR_RESET_FILT, + mmio + NI6527_CLR_REG); + writeb(NI6527_CTRL_DISABLE_IRQS, mmio + NI6527_CTRL_REG); } static int ni6527_auto_attach(struct comedi_device *dev, @@ -332,75 +364,69 @@ static int ni6527_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + ret = comedi_pci_enable(dev); if (ret) return ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) + devpriv->mmio_base = pci_ioremap_bar(pcidev, 1); + if (!devpriv->mmio_base) return -ENOMEM; - devpriv->mite = mite_alloc(pcidev); - if (!devpriv->mite) - return -ENOMEM; + /* make sure this is actually a 6527 device */ + if (readb(devpriv->mmio_base + NI6527_ID_REG) != 0x27) + return -ENODEV; - ret = mite_setup(devpriv->mite); - if (ret < 0) { - dev_err(dev->class_dev, "error setting up mite\n"); - return ret; - } + ni6527_reset(dev); - dev_info(dev->class_dev, "board: %s, ID=0x%02x\n", dev->board_name, - readb(devpriv->mite->daq_io_addr + ID_Register)); + ret = request_irq(pcidev->irq, ni6527_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; + /* Digital Input subdevice */ s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 24; - s->range_table = &range_digital; - s->maxdata = 1; - s->insn_config = ni6527_di_insn_config; - s->insn_bits = ni6527_di_insn_bits; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = ni6527_di_insn_config; + s->insn_bits = ni6527_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 24; - s->range_table = &range_unknown; /* FIXME: actually conductance */ - s->maxdata = 1; - s->insn_bits = ni6527_do_insn_bits; - + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ni6527_do_insn_bits; + + /* Edge detection interrupt subdevice */ s = &dev->subdevices[2]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = 1; - s->range_table = &range_unknown; - s->maxdata = 1; - s->do_cmdtest = ni6527_intr_cmdtest; - s->do_cmd = ni6527_intr_cmd; - s->cancel = ni6527_intr_cancel; - s->insn_bits = ni6527_intr_insn_bits; - s->insn_config = ni6527_intr_insn_config; - - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0)); - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(1)); - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(2)); - - writeb(ClrEdge | ClrOverflow | ClrFilter | ClrInterval, - devpriv->mite->daq_io_addr + Clear_Register); - writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); - - ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt, - IRQF_SHARED, DRIVER_NAME, dev); - if (ret < 0) - dev_warn(dev->class_dev, "irq not available\n"); - else - dev->irq = mite_irq(devpriv->mite); + if (dev->irq) { + dev->read_subdev = s; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = ni6527_intr_insn_config; + s->insn_bits = ni6527_intr_insn_bits; + s->do_cmdtest = ni6527_intr_cmdtest; + s->do_cmd = ni6527_intr_cmd; + s->cancel = ni6527_intr_cancel; + } else { + s->type = COMEDI_SUBD_UNUSED; + } return 0; } @@ -409,23 +435,18 @@ static void ni6527_detach(struct comedi_device *dev) { struct ni6527_private *devpriv = dev->private; - if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) - writeb(0x00, - devpriv->mite->daq_io_addr + Master_Interrupt_Control); + if (devpriv && devpriv->mmio_base) + ni6527_reset(dev); if (dev->irq) free_irq(dev->irq, dev); - if (devpriv && devpriv->mite) { - mite_unsetup(devpriv->mite); - mite_free(devpriv->mite); - } comedi_pci_disable(dev); } static struct comedi_driver ni6527_driver = { - .driver_name = DRIVER_NAME, - .module = THIS_MODULE, - .auto_attach = ni6527_auto_attach, - .detach = ni6527_detach, + .driver_name = "ni_6527", + .module = THIS_MODULE, + .auto_attach = ni6527_auto_attach, + .detach = ni6527_detach, }; static int ni6527_pci_probe(struct pci_dev *dev, @@ -442,7 +463,7 @@ static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = { MODULE_DEVICE_TABLE(pci, ni6527_pci_table); static struct pci_driver ni6527_pci_driver = { - .name = DRIVER_NAME, + .name = "ni_6527", .id_table = ni6527_pci_table, .probe = ni6527_pci_probe, .remove = comedi_pci_auto_unconfig, @@ -450,5 +471,5 @@ static struct pci_driver ni6527_pci_driver = { module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for National Instruments PCI-6527"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index 3607336dafe2..8a991dcab24a 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -1213,7 +1213,6 @@ static int ni_660x_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = ni_660x_dio_insn_bits; s->insn_config = ni_660x_dio_insn_config; - s->io_bits = 0; /* all bits default to input */ /* we use the ioconfig registers to control dio direction, so zero output enables in stc dio control reg */ ni_660x_write_register(dev, 0, 0, STCDIOControl); diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index e2926ce3fb24..e4414cf110e7 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -136,20 +136,15 @@ static int ni_670x_ao_rinsn(struct comedi_device *dev, static int ni_670x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni_670x_private *devpriv = dev->private; void __iomem *io_addr = devpriv->mite->daq_io_addr + DIO_PORT0_DATA_OFFSET; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) writel(s->state, io_addr); - } data[1] = readl(io_addr); diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 2512ce8dfcaa..63c847932eb8 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -154,7 +154,7 @@ struct a2150_private { volatile unsigned int count; /* number of data points left to be taken */ unsigned int dma; /* dma channel */ - s16 *dma_buffer; /* dma buffer */ + uint16_t *dma_buffer; /* dma buffer */ unsigned int dma_transfer_size; /* size in bytes of dma transfers */ int irq_dma_bits; /* irq/dma register bits */ int config_bits; /* config register bits */ @@ -192,7 +192,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) struct comedi_async *async; struct comedi_cmd *cmd; unsigned int max_points, num_points, residue, leftover; - short dpnt; + unsigned short dpnt; static const int sample_size = sizeof(devpriv->dma_buffer[0]); if (!dev->attached) { @@ -684,13 +684,12 @@ static int a2150_set_chanlist(struct comedi_device *dev, devpriv->config_bits |= CHANNEL_BITS(0x4 | start_channel); break; case 2: - if (start_channel == 0) { + if (start_channel == 0) devpriv->config_bits |= CHANNEL_BITS(0x2); - } else if (start_channel == 2) { + else if (start_channel == 2) devpriv->config_bits |= CHANNEL_BITS(0x3); - } else { + else return -1; - } break; case 4: devpriv->config_bits |= CHANNEL_BITS(0x1); diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index b9122fd835e1..10e3e9475ee2 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -1,247 +1,193 @@ /* - comedi/drivers/ni_at_ao.c - Driver for NI AT-AO-6/10 boards - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000,2002 David A. Schleef <ds@schleef.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, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: ni_at_ao -Description: National Instruments AT-AO-6/10 -Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10) -Status: should work -Author: ds -Updated: Sun Dec 26 12:26:28 EST 2004 - -Configuration options: - [0] - I/O port base address - [1] - IRQ (unused) - [2] - DMA (unused) - [3] - analog output range, set by jumpers on hardware (0 for -10 to 10V - bipolar, 1 for 0V to 10V unipolar) - -*/ + * ni_at_ao.c + * Driver for NI AT-AO-6/10 boards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000,2002 David A. Schleef <ds@schleef.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, 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. + */ + /* - * Register-level programming information can be found in NI - * document 320379.pdf. + * Driver: ni_at_ao + * Description: National Instruments AT-AO-6/10 + * Devices: (National Instruments) AT-AO-6 [at-ao-6] + * (National Instruments) AT-AO-10 [at-ao-10] + * Status: should work + * Author: David A. Schleef <ds@schleef.org> + * Updated: Sun Dec 26 12:26:28 EST 2004 + * + * Configuration options: + * [0] - I/O port base address + * [1] - IRQ (unused) + * [2] - DMA (unused) + * [3] - analog output range, set by jumpers on hardware + * 0 for -10 to 10V bipolar + * 1 for 0V to 10V unipolar */ #include <linux/module.h> -#include "../comedidev.h" -/* board egisters */ -/* registers with _2_ are accessed when GRP2WR is set in CFG1 */ +#include "../comedidev.h" -#define ATAO_SIZE 0x20 - -#define ATAO_2_DMATCCLR 0x00 /* W 16 */ -#define ATAO_DIN 0x00 /* R 16 */ -#define ATAO_DOUT 0x00 /* W 16 */ - -#define ATAO_CFG2 0x02 /* W 16 */ -#define CALLD1 0x8000 -#define CALLD0 0x4000 -#define FFRTEN 0x2000 -#define DAC2S8 0x1000 -#define DAC2S6 0x0800 -#define DAC2S4 0x0400 -#define DAC2S2 0x0200 -#define DAC2S0 0x0100 -#define LDAC8 0x0080 -#define LDAC6 0x0040 -#define LDAC4 0x0020 -#define LDAC2 0x0010 -#define LDAC0 0x0008 -#define PROMEN 0x0004 -#define SCLK 0x0002 -#define SDATA 0x0001 - -#define ATAO_2_INT1CLR 0x02 /* W 16 */ - -#define ATAO_CFG3 0x04 /* W 16 */ -#define DMAMODE 0x0040 -#define CLKOUT 0x0020 -#define RCLKEN 0x0010 -#define DOUTEN2 0x0008 -#define DOUTEN1 0x0004 -#define EN2_5V 0x0002 -#define SCANEN 0x0001 - -#define ATAO_2_INT2CLR 0x04 /* W 16 */ - -#define ATAO_82C53_BASE 0x06 /* RW 8 */ - -#define ATAO_82C53_CNTR1 0x06 /* RW 8 */ -#define ATAO_82C53_CNTR2 0x07 /* RW 8 */ -#define ATAO_82C53_CNTR3 0x08 /* RW 8 */ -#define ATAO_82C53_CNTRCMD 0x09 /* W 8 */ -#define CNTRSEL1 0x80 -#define CNTRSEL0 0x40 -#define RWSEL1 0x20 -#define RWSEL0 0x10 -#define MODESEL2 0x08 -#define MODESEL1 0x04 -#define MODESEL0 0x02 -#define BCDSEL 0x01 - /* read-back command */ -#define COUNT 0x20 -#define STATUS 0x10 -#define CNTR3 0x08 -#define CNTR2 0x04 -#define CNTR1 0x02 - /* status */ -#define OUT 0x80 -#define _NULL 0x40 -#define RW1 0x20 -#define RW0 0x10 -#define MODE2 0x08 -#define MODE1 0x04 -#define MODE0 0x02 -#define BCD 0x01 - -#define ATAO_2_RTSISHFT 0x06 /* W 8 */ -#define RSI 0x01 - -#define ATAO_2_RTSISTRB 0x07 /* W 8 */ - -#define ATAO_CFG1 0x0a /* W 16 */ -#define EXTINT2EN 0x8000 -#define EXTINT1EN 0x4000 -#define CNTINT2EN 0x2000 -#define CNTINT1EN 0x1000 -#define TCINTEN 0x0800 -#define CNT1SRC 0x0400 -#define CNT2SRC 0x0200 -#define FIFOEN 0x0100 -#define GRP2WR 0x0080 -#define EXTUPDEN 0x0040 -#define DMARQ 0x0020 -#define DMAEN 0x0010 -#define CH_mask 0x000f -#define ATAO_STATUS 0x0a /* R 16 */ -#define FH 0x0040 -#define FE 0x0020 -#define FF 0x0010 -#define INT2 0x0008 -#define INT1 0x0004 -#define TCINT 0x0002 -#define PROMOUT 0x0001 - -#define ATAO_FIFO_WRITE 0x0c /* W 16 */ -#define ATAO_FIFO_CLEAR 0x0c /* R 16 */ -#define ATAO_DACn(x) (0x0c + 2*(x)) /* W */ +#include "8253.h" /* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. + * Register map + * + * Register-level programming information can be found in NI + * document 320379.pdf. */ +#define ATAO_DIO_REG 0x00 +#define ATAO_CFG2_REG 0x02 +#define ATAO_CFG2_CALLD_NOP (0 << 14) +#define ATAO_CFG2_CALLD(x) ((((x) >> 3) + 1) << 14) +#define ATAO_CFG2_FFRTEN (1 << 13) +#define ATAO_CFG2_DACS(x) (1 << (((x) / 2) + 8)) +#define ATAO_CFG2_LDAC(x) (1 << (((x) / 2) + 3)) +#define ATAO_CFG2_PROMEN (1 << 2) +#define ATAO_CFG2_SCLK (1 << 1) +#define ATAO_CFG2_SDATA (1 << 0) +#define ATAO_CFG3_REG 0x04 +#define ATAO_CFG3_DMAMODE (1 << 6) +#define ATAO_CFG3_CLKOUT (1 << 5) +#define ATAO_CFG3_RCLKEN (1 << 4) +#define ATAO_CFG3_DOUTEN2 (1 << 3) +#define ATAO_CFG3_DOUTEN1 (1 << 2) +#define ATAO_CFG3_EN2_5V (1 << 1) +#define ATAO_CFG3_SCANEN (1 << 0) +#define ATAO_82C53_BASE 0x06 +#define ATAO_CFG1_REG 0x0a +#define ATAO_CFG1_EXTINT2EN (1 << 15) +#define ATAO_CFG1_EXTINT1EN (1 << 14) +#define ATAO_CFG1_CNTINT2EN (1 << 13) +#define ATAO_CFG1_CNTINT1EN (1 << 12) +#define ATAO_CFG1_TCINTEN (1 << 11) +#define ATAO_CFG1_CNT1SRC (1 << 10) +#define ATAO_CFG1_CNT2SRC (1 << 9) +#define ATAO_CFG1_FIFOEN (1 << 8) +#define ATAO_CFG1_GRP2WR (1 << 7) +#define ATAO_CFG1_EXTUPDEN (1 << 6) +#define ATAO_CFG1_DMARQ (1 << 5) +#define ATAO_CFG1_DMAEN (1 << 4) +#define ATAO_CFG1_CH(x) (((x) & 0xf) << 0) +#define ATAO_STATUS_REG 0x0a +#define ATAO_STATUS_FH (1 << 6) +#define ATAO_STATUS_FE (1 << 5) +#define ATAO_STATUS_FF (1 << 4) +#define ATAO_STATUS_INT2 (1 << 3) +#define ATAO_STATUS_INT1 (1 << 2) +#define ATAO_STATUS_TCINT (1 << 1) +#define ATAO_STATUS_PROMOUT (1 << 0) +#define ATAO_FIFO_WRITE_REG 0x0c +#define ATAO_FIFO_CLEAR_REG 0x0c +#define ATAO_AO_REG(x) (0x0c + ((x) * 2)) + +/* registers with _2_ are accessed when GRP2WR is set in CFG1 */ +#define ATAO_2_DMATCCLR_REG 0x00 +#define ATAO_2_INT1CLR_REG 0x02 +#define ATAO_2_INT2CLR_REG 0x04 +#define ATAO_2_RTSISHFT_REG 0x06 +#define ATAO_2_RTSISHFT_RSI (1 << 0) +#define ATAO_2_RTSISTRB_REG 0x07 + struct atao_board { const char *name; int n_ao_chans; }; -struct atao_private { +static const struct atao_board atao_boards[] = { + { + .name = "at-ao-6", + .n_ao_chans = 6, + }, { + .name = "at-ao-10", + .n_ao_chans = 10, + }, +}; +struct atao_private { unsigned short cfg1; - unsigned short cfg2; unsigned short cfg3; /* Used for AO readback */ unsigned int ao_readback[10]; + + /* Used for caldac readback */ + unsigned char caldac[21]; }; -static void atao_reset(struct comedi_device *dev) +static void atao_select_reg_group(struct comedi_device *dev, int group) { struct atao_private *devpriv = dev->private; - /* This is the reset sequence described in the manual */ - - devpriv->cfg1 = 0; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - - outb(RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); - outb(0x03, dev->iobase + ATAO_82C53_CNTR1); - outb(CNTRSEL0 | RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); - - devpriv->cfg2 = 0; - outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); - - devpriv->cfg3 = 0; - outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); - - inw(dev->iobase + ATAO_FIFO_CLEAR); - - devpriv->cfg1 |= GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - - outw(0, dev->iobase + ATAO_2_INT1CLR); - outw(0, dev->iobase + ATAO_2_INT2CLR); - outw(0, dev->iobase + ATAO_2_DMATCCLR); - - devpriv->cfg1 &= ~GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); + if (group) + devpriv->cfg1 |= ATAO_CFG1_GRP2WR; + else + devpriv->cfg1 &= ~ATAO_CFG1_GRP2WR; + outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG); } -static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int atao_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; int i; - int chan = CR_CHAN(insn->chanspec); - short bits; + + if (chan == 0) + atao_select_reg_group(dev, 1); for (i = 0; i < insn->n; i++) { - bits = data[i] - 0x800; - if (chan == 0) { - devpriv->cfg1 |= GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - } - outw(bits, dev->iobase + ATAO_DACn(chan)); - if (chan == 0) { - devpriv->cfg1 &= ~GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - } - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + devpriv->ao_readback[chan] = val; + + /* munge offset binary (unsigned) to two's complement */ + val = comedi_offset_munge(s, val); + outw(val, dev->iobase + ATAO_AO_REG(chan)); } - return i; + if (chan == 0) + atao_select_reg_group(dev, 0); + + return insn->n; } -static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int atao_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[chan]; - return i; + return insn->n; } static int atao_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outw(s->state, dev->iobase + ATAO_DOUT); - } + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + ATAO_DIO_REG); - data[1] = inw(dev->iobase + ATAO_DIN); + data[1] = inw(dev->iobase + ATAO_DIO_REG); return insn->n; } @@ -266,57 +212,128 @@ static int atao_dio_insn_config(struct comedi_device *dev, return ret; if (s->io_bits & 0x0f) - devpriv->cfg3 |= DOUTEN1; + devpriv->cfg3 |= ATAO_CFG3_DOUTEN1; else - devpriv->cfg3 &= ~DOUTEN1; + devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN1; if (s->io_bits & 0xf0) - devpriv->cfg3 |= DOUTEN2; + devpriv->cfg3 |= ATAO_CFG3_DOUTEN2; else - devpriv->cfg3 &= ~DOUTEN2; + devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN2; - outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); + outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG); return insn->n; } /* - * Figure 2-1 in the manual shows 3 chips labeled DAC8800, which - * are 8-channel 8-bit DACs. These are most likely the calibration - * DACs. It is not explicitly stated in the manual how to access - * the caldacs, but we can guess. + * There are three DAC8800 TrimDACs on the board. These are 8-channel, + * 8-bit DACs that are used to calibrate the Analog Output channels. + * The factory default calibration values are stored in the EEPROM. + * The TrimDACs, and EEPROM addresses, are mapped as: + * + * Channel EEPROM Description + * ----------------- ------ ----------------------------------- + * 0 - DAC0 Chan 0 0x30 AO Channel 0 Offset + * 1 - DAC0 Chan 1 0x31 AO Channel 0 Gain + * 2 - DAC0 Chan 2 0x32 AO Channel 1 Offset + * 3 - DAC0 Chan 3 0x33 AO Channel 1 Gain + * 4 - DAC0 Chan 4 0x34 AO Channel 2 Offset + * 5 - DAC0 Chan 5 0x35 AO Channel 2 Gain + * 6 - DAC0 Chan 6 0x36 AO Channel 3 Offset + * 7 - DAC0 Chan 7 0x37 AO Channel 3 Gain + * 8 - DAC1 Chan 0 0x38 AO Channel 4 Offset + * 9 - DAC1 Chan 1 0x39 AO Channel 4 Gain + * 10 - DAC1 Chan 2 0x3a AO Channel 5 Offset + * 11 - DAC1 Chan 3 0x3b AO Channel 5 Gain + * 12 - DAC1 Chan 4 0x3c 2.5V Offset + * 13 - DAC1 Chan 5 0x3d AO Channel 6 Offset (at-ao-10 only) + * 14 - DAC1 Chan 6 0x3e AO Channel 6 Gain (at-ao-10 only) + * 15 - DAC1 Chan 7 0x3f AO Channel 7 Offset (at-ao-10 only) + * 16 - DAC2 Chan 0 0x40 AO Channel 7 Gain (at-ao-10 only) + * 17 - DAC2 Chan 1 0x41 AO Channel 8 Offset (at-ao-10 only) + * 18 - DAC2 Chan 2 0x42 AO Channel 8 Gain (at-ao-10 only) + * 19 - DAC2 Chan 3 0x43 AO Channel 9 Offset (at-ao-10 only) + * 20 - DAC2 Chan 4 0x44 AO Channel 9 Gain (at-ao-10 only) + * DAC2 Chan 5 0x45 Reserved + * DAC2 Chan 6 0x46 Reserved + * DAC2 Chan 7 0x47 Reserved */ +static int atao_calib_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int bitstring; + unsigned int val; + int bit; + + if (insn->n == 0) + return 0; + + devpriv->caldac[chan] = data[insn->n - 1] & s->maxdata; + + /* write the channel and last data value to the caldac */ + bitstring = ((chan & 0x7) << 8) | devpriv->caldac[chan]; + + /* clock the bitstring to the caldac; MSB -> LSB */ + for (bit = 1 << 10; bit; bit >>= 1) { + val = (bit & bitstring) ? ATAO_CFG2_SDATA : 0; + + outw(val, dev->iobase + ATAO_CFG2_REG); + outw(val | ATAO_CFG2_SCLK, dev->iobase + ATAO_CFG2_REG); + } + + /* strobe the caldac to load the value */ + outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG); + outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); + + return insn->n; +} + static int atao_calib_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; + for (i = 0; i < insn->n; i++) - data[i] = 0; /* XXX */ + data[i] = devpriv->caldac[chan]; + return insn->n; } -static int atao_calib_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void atao_reset(struct comedi_device *dev) { struct atao_private *devpriv = dev->private; - unsigned int bitstring, bit; - unsigned int chan = CR_CHAN(insn->chanspec); - bitstring = ((chan & 0x7) << 8) | (data[insn->n - 1] & 0xff); + /* This is the reset sequence described in the manual */ - for (bit = 1 << (11 - 1); bit; bit >>= 1) { - outw(devpriv->cfg2 | ((bit & bitstring) ? SDATA : 0), - dev->iobase + ATAO_CFG2); - outw(devpriv->cfg2 | SCLK | ((bit & bitstring) ? SDATA : 0), - dev->iobase + ATAO_CFG2); - } - /* strobe the appropriate caldac */ - outw(devpriv->cfg2 | (((chan >> 3) + 1) << 14), - dev->iobase + ATAO_CFG2); - outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); + devpriv->cfg1 = 0; + outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG); - return insn->n; + /* Put outputs of counter 1 and counter 2 in a high state */ + i8254_load(dev->iobase + ATAO_82C53_BASE, 0, + 0, 0x0003, I8254_MODE4 | I8254_BINARY); + i8254_set_mode(dev->iobase + ATAO_82C53_BASE, 0, + 1, I8254_MODE4 | I8254_BINARY); + + outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); + + devpriv->cfg3 = 0; + outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG); + + inw(dev->iobase + ATAO_FIFO_CLEAR_REG); + + atao_select_reg_group(dev, 1); + outw(0, dev->iobase + ATAO_2_INT1CLR_REG); + outw(0, dev->iobase + ATAO_2_INT2CLR_REG); + outw(0, dev->iobase + ATAO_2_DMATCCLR_REG); + atao_select_reg_group(dev, 0); } static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -324,12 +341,9 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) const struct atao_board *board = comedi_board(dev); struct atao_private *devpriv; struct comedi_subdevice *s; - int ao_unipolar; int ret; - ao_unipolar = it->options[3]; - - ret = comedi_request_region(dev, it->options[0], ATAO_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x20); if (ret) return ret; @@ -341,60 +355,44 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; + /* Analog Output subdevice */ s = &dev->subdevices[0]; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_ao_chans; - s->maxdata = (1 << 12) - 1; - if (ao_unipolar) - s->range_table = &range_unipolar10; - else - s->range_table = &range_bipolar10; - s->insn_write = &atao_ao_winsn; - s->insn_read = &atao_ao_rinsn; - + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_ao_chans; + s->maxdata = 0x0fff; + s->range_table = it->options[3] ? &range_unipolar10 : &range_bipolar10; + s->insn_write = atao_ao_insn_write; + s->insn_read = atao_ao_insn_read; + + /* Digital I/O subdevice */ s = &dev->subdevices[1]; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = atao_dio_insn_bits; - s->insn_config = atao_dio_insn_config; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = atao_dio_insn_bits; + s->insn_config = atao_dio_insn_config; - s = &dev->subdevices[2]; /* caldac subdevice */ - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = 21; - s->maxdata = 0xff; - s->insn_read = atao_calib_insn_read; - s->insn_write = atao_calib_insn_write; - + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = (board->n_ao_chans * 2) + 1; + s->maxdata = 0xff; + s->insn_read = atao_calib_insn_read; + s->insn_write = atao_calib_insn_write; + + /* EEPROM subdevice */ s = &dev->subdevices[3]; - /* eeprom subdevice */ - /* s->type=COMEDI_SUBD_EEPROM; */ - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; atao_reset(dev); - printk(KERN_INFO "\n"); - return 0; } -static const struct atao_board atao_boards[] = { - { - .name = "ai-ao-6", - .n_ao_chans = 6, - }, { - .name = "ai-ao-10", - .n_ao_chans = 10, - }, -}; - static struct comedi_driver ni_at_ao_driver = { .driver_name = "ni_at_ao", .module = THIS_MODULE, @@ -407,5 +405,5 @@ static struct comedi_driver ni_at_ao_driver = { module_comedi_driver(ni_at_ao_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for NI AT-AO-6/10 boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index bb3491f5ad21..a9f7d40d6db2 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -558,13 +558,12 @@ static int atmio16d_ao_insn_write(struct comedi_device *dev, static int atmio16d_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] | data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + MIO_16_DIG_OUT_REG); - } + data[1] = inw(dev->iobase + MIO_16_DIG_IN_REG); return insn->n; diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 404f83de276d..e4cdca349157 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -72,18 +72,22 @@ Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf static int daq700_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + unsigned int mask; + unsigned int val; - if (data[0] & 0xff) + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0xff) outb(s->state & 0xff, dev->iobase + DIO_W); } - data[1] = s->state & 0xff; - data[1] |= inb(dev->iobase + DIO_R) << 8; + val = s->state & 0xff; + val |= inb(dev->iobase + DIO_R) << 8; + + data[1] = val; return insn->n; } @@ -212,7 +216,6 @@ static int daq700_auto_attach(struct comedi_device *dev, s->maxdata = 1; s->insn_bits = daq700_dio_insn_bits; s->insn_config = daq700_dio_insn_config; - s->state = 0; s->io_bits = 0x00ff; /* DAQCard-700 ai */ diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 1add114dc0bc..0512445df08e 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -73,7 +73,6 @@ #include "ni_labpc_isadma.h" #define LABPC_SIZE 0x20 /* size of ISA io region */ -#define LABPC_TIMER_BASE 500 /* 2 MHz master clock */ #define LABPC_ADC_TIMEOUT 1000 enum scan_mode { @@ -201,12 +200,6 @@ static int labpc_counter_set_mode(struct comedi_device *dev, return i8254_set_mode(base_address, 0, counter_number, mode); } -static bool labpc_range_is_unipolar(struct comedi_subdevice *s, - unsigned int range) -{ - return s->range_table->range[range].min >= 0; -} - static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct labpc_private *devpriv = dev->private; @@ -272,7 +265,7 @@ static void labpc_setup_cmd6_reg(struct comedi_device *dev, devpriv->cmd6 &= ~CMD6_NRSE; /* bipolar or unipolar range? */ - if (labpc_range_is_unipolar(s, range)) + if (comedi_range_is_unipolar(s, range)) devpriv->cmd6 |= CMD6_ADCUNI; else devpriv->cmd6 &= ~CMD6_ADCUNI; @@ -465,13 +458,13 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, * clock speed on convert and scan counters) */ devpriv->divisor_b0 = (scan_period - 1) / - (LABPC_TIMER_BASE * max_counter_value) + 1; + (I8254_OSC_BASE_2MHZ * max_counter_value) + 1; if (devpriv->divisor_b0 < min_counter_value) devpriv->divisor_b0 = min_counter_value; if (devpriv->divisor_b0 > max_counter_value) devpriv->divisor_b0 = max_counter_value; - base_period = LABPC_TIMER_BASE * devpriv->divisor_b0; + base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0; /* set a0 for conversion frequency and b1 for scan frequency */ switch (cmd->flags & TRIG_ROUND_MASK) { @@ -516,22 +509,20 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, * calculate cascaded counter values * that give desired scan timing */ - i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE, - &(devpriv->divisor_b1), - &(devpriv->divisor_b0), - &scan_period, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor_b1, + &devpriv->divisor_b0, + &scan_period, cmd->flags); labpc_set_ai_scan_period(cmd, mode, scan_period); } else if (convert_period) { /* * calculate cascaded counter values * that give desired conversion timing */ - i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE, - &(devpriv->divisor_a0), - &(devpriv->divisor_b0), - &convert_period, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor_a0, + &devpriv->divisor_b0, + &convert_period, cmd->flags); labpc_set_ai_convert_period(cmd, mode, convert_period); } } @@ -902,7 +893,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int labpc_drain_fifo(struct comedi_device *dev) { struct labpc_private *devpriv = dev->private; - short data; + unsigned short data; struct comedi_async *async = dev->read_subdev->async; const int timeout = 10000; unsigned int i; @@ -1046,7 +1037,7 @@ static int labpc_ao_insn_write(struct comedi_device *dev, /* set range */ if (board->is_labpc1200) { range = CR_RANGE(insn->chanspec); - if (labpc_range_is_unipolar(s, range)) + if (comedi_range_is_unipolar(s, range)) devpriv->cmd6 |= CMD6_DACUNI(channel); else devpriv->cmd6 &= ~CMD6_DACUNI(channel); diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 4e02770e834b..5113397bfecf 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1292,7 +1292,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev, struct comedi_cmd *cmd = &async->cmd; int chan; int i; - short d; + unsigned short d; u32 packed_data; int range; int err = 1; @@ -1403,7 +1403,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev, int i; if (board->reg_type == ni_reg_611x) { - short data[2]; + unsigned short data[2]; u32 dl; for (i = 0; i < n / 2; i++) { @@ -1420,7 +1420,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev, cfc_write_to_buffer(s, data[0]); } } else if (board->reg_type == ni_reg_6143) { - short data[2]; + unsigned short data[2]; u32 dl; /* This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed */ @@ -1511,9 +1511,9 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; - short data[2]; + unsigned short data[2]; u32 dl; - short fifo_empty; + unsigned short fifo_empty; int i; if (board->reg_type == ni_reg_611x) { @@ -1577,7 +1577,7 @@ static void get_last_sample_611x(struct comedi_device *dev) const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv __maybe_unused = dev->private; struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; - short data; + unsigned short data; u32 dl; if (board->reg_type != ni_reg_611x) @@ -1596,7 +1596,7 @@ static void get_last_sample_6143(struct comedi_device *dev) const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv __maybe_unused = dev->private; struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; - short data; + unsigned short data; u32 dl; if (board->reg_type != ni_reg_6143) @@ -1621,7 +1621,7 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_async *async = s->async; unsigned int i; unsigned int length = num_bytes / bytes_per_sample(s); - short *array = data; + unsigned short *array = data; unsigned int *larray = data; for (i = 0; i < length; i++) { @@ -2873,7 +2873,7 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int i; unsigned int offset; unsigned int length = num_bytes / sizeof(short); - short *array = data; + unsigned short *array = data; offset = 1 << (board->aobits - 1); for (i = 0; i < length; i++) { @@ -3547,28 +3547,22 @@ static int ni_dio_insn_config(struct comedi_device *dev, static int ni_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct ni_private *devpriv = dev->private; -#ifdef DEBUG_DIO - printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], data[1]); -#endif - - if (data[0]) { - /* Perform check to make sure we're not using the - serial part of the dio */ - if ((data[0] & (DIO_SDIN | DIO_SDOUT)) - && devpriv->serial_interval_ns) - return -EBUSY; + /* Make sure we're not using the serial part of the dio */ + if ((data[0] & (DIO_SDIN | DIO_SDOUT)) && devpriv->serial_interval_ns) + return -EBUSY; - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { devpriv->dio_output &= ~DIO_Parallel_Data_Mask; devpriv->dio_output |= DIO_Parallel_Data_Out(s->state); devpriv->stc_writew(dev, devpriv->dio_output, DIO_Output_Register); } + data[1] = devpriv->stc_readw(dev, DIO_Parallel_Input_Register); return insn->n; @@ -3598,16 +3592,9 @@ static int ni_m_series_dio_insn_bits(struct comedi_device *dev, { struct ni_private *devpriv __maybe_unused = dev->private; -#ifdef DEBUG_DIO - printk("ni_m_series_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], - data[1]); -#endif - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) ni_writel(s->state, M_Offset_Static_Digital_Output); - } + data[1] = ni_readl(M_Offset_Static_Digital_Input); return insn->n; @@ -5355,20 +5342,20 @@ static int ni_config_filter(struct comedi_device *dev, unsigned pfi_channel, static int ni_pfi_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv __maybe_unused = dev->private; - if ((board->reg_type & ni_reg_m_series_mask) == 0) { + if (!(board->reg_type & ni_reg_m_series_mask)) return -ENOTSUPP; - } - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + + if (comedi_dio_update_state(s, data)) ni_writew(s->state, M_Offset_PFI_DO); - } + data[1] = ni_readw(M_Offset_PFI_DI); + return insn->n; } diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index fad81bc97b6e..e3a8fa96d9b3 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -406,9 +406,9 @@ static irqreturn_t nidio_interrupt(int irq, void *d) struct mite_struct *mite = devpriv->mite; /* int i, j; */ - long int AuxData = 0; - short data1 = 0; - short data2 = 0; + unsigned int auxdata = 0; + unsigned short data1 = 0; + unsigned short data2 = 0; int flags; int status; int work = 0; @@ -481,11 +481,11 @@ static irqreturn_t nidio_interrupt(int irq, void *d) ); goto out; } - AuxData = + auxdata = readl(devpriv->mite->daq_io_addr + Group_1_FIFO); - data1 = AuxData & 0xffff; - data2 = (AuxData & 0xffff0000) >> 16; + data1 = auxdata & 0xffff; + data2 = (auxdata & 0xffff0000) >> 16; comedi_buf_put(async, data1); comedi_buf_put(async, data2); /* DPRINTK("read:%d, %d\n",data1,data2); */ @@ -657,15 +657,14 @@ static int ni_pcidio_insn_config(struct comedi_device *dev, static int ni_pcidio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct nidio96_private *devpriv = dev->private; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) writel(s->state, devpriv->mite->daq_io_addr + Port_IO(0)); - } + data[1] = readl(devpriv->mite->daq_io_addr + Port_IO(0)); return insn->n; diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index 11bf0aab82ea..f0630b7897b5 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -1491,7 +1491,7 @@ struct ni_board_struct { unsigned short pwm_up_count; \ unsigned short pwm_down_count; \ \ - short ai_fifo_buffer[0x2000]; \ + unsigned short ai_fifo_buffer[0x2000]; \ uint8_t eeprom_buffer[M_SERIES_EEPROM_SIZE]; \ uint32_t serial_number; \ \ diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index e859f85a8e17..f0fc123ef566 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -1,258 +1,295 @@ /* - comedi/drivers/pcl711.c - hardware driver for PC-LabCard PCL-711 and AdSys ACL-8112 - and compatibles - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - Janne Jalkanen <jalkanen@cs.hut.fi> - Eric Bunn <ebu@cs.hut.fi> - - 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. + * pcl711.c + * Comedi driver for PC-LabCard PCL-711 and AdSys ACL-8112 and compatibles + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * Janne Jalkanen <jalkanen@cs.hut.fi> + * Eric Bunn <ebu@cs.hut.fi> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.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, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -/* -Driver: pcl711 -Description: Advantech PCL-711 and 711b, ADLink ACL-8112 -Author: ds, Janne Jalkanen <jalkanen@cs.hut.fi>, Eric Bunn <ebu@cs.hut.fi> -Status: mostly complete -Devices: [Advantech] PCL-711 (pcl711), PCL-711B (pcl711b), - [AdLink] ACL-8112HG (acl8112hg), ACL-8112DG (acl8112dg) - -Since these boards do not have DMA or FIFOs, only immediate mode is -supported. - -*/ /* - Dave Andruczyk <dave@tech.buffalostate.edu> also wrote a - driver for the PCL-711. I used a few ideas from his driver - here. His driver also has more comments, if you are - interested in understanding how this driver works. - http://tech.buffalostate.edu/~dave/driver/ - - The ACL-8112 driver was hacked from the sources of the PCL-711 - driver (the 744 chip used on the 8112 is almost the same as - the 711b chip, but it has more I/O channels) by - Janne Jalkanen (jalkanen@cs.hut.fi) and - Erik Bunn (ebu@cs.hut.fi). Remerged with the PCL-711 driver - by ds. - - [acl-8112] - This driver supports both TRIGNOW and TRIGCLK, - but does not yet support DMA transfers. It also supports - both high (HG) and low (DG) versions of the card, though - the HG version has been untested. - + * Driver: pcl711 + * Description: Advantech PCL-711 and 711b, ADLink ACL-8112 + * Devices: (Advantech) PCL-711 [pcl711] + * (Advantech) PCL-711B [pcl711b] + * (AdLink) ACL-8112HG [acl8112hg] + * (AdLink) ACL-8112DG [acl8112dg] + * Author: David A. Schleef <ds@schleef.org> + * Janne Jalkanen <jalkanen@cs.hut.fi> + * Eric Bunn <ebu@cs.hut.fi> + * Updated: + * Status: mostly complete + * + * Configuration Options: + * [0] - I/O port base + * [1] - IRQ, optional */ #include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> -#include "../comedidev.h" -#include <linux/delay.h> +#include "../comedidev.h" #include "comedi_fc.h" #include "8253.h" -#define PCL711_SIZE 16 - -#define PCL711_CTR0 0 -#define PCL711_CTR1 1 -#define PCL711_CTR2 2 -#define PCL711_CTRCTL 3 -#define PCL711_AD_LO 4 -#define PCL711_DA0_LO 4 -#define PCL711_AD_HI 5 -#define PCL711_DA0_HI 5 -#define PCL711_DI_LO 6 -#define PCL711_DA1_LO 6 -#define PCL711_DI_HI 7 -#define PCL711_DA1_HI 7 -#define PCL711_CLRINTR 8 -#define PCL711_GAIN 9 -#define PCL711_MUX 10 -#define PCL711_MODE 11 -#define PCL711_SOFTTRIG 12 -#define PCL711_DO_LO 13 -#define PCL711_DO_HI 14 - -static const struct comedi_lrange range_pcl711b_ai = { 5, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(0.3125) - } +/* + * I/O port register map + */ +#define PCL711_TIMER_BASE 0x00 +#define PCL711_AI_LSB_REG 0x04 +#define PCL711_AI_MSB_REG 0x05 +#define PCL711_AI_MSB_DRDY (1 << 4) +#define PCL711_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL711_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL711_DI_LSB_REG 0x06 +#define PCL711_DI_MSB_REG 0x07 +#define PCL711_INT_STAT_REG 0x08 +#define PCL711_INT_STAT_CLR (0 << 0) /* any value will work */ +#define PCL711_AI_GAIN_REG 0x09 +#define PCL711_AI_GAIN(x) (((x) & 0xf) << 0) +#define PCL711_MUX_REG 0x0a +#define PCL711_MUX_CHAN(x) (((x) & 0xf) << 0) +#define PCL711_MUX_CS0 (1 << 4) +#define PCL711_MUX_CS1 (1 << 5) +#define PCL711_MUX_DIFF (PCL711_MUX_CS0 | PCL711_MUX_CS1) +#define PCL711_MODE_REG 0x0b +#define PCL711_MODE_DEFAULT (0 << 0) +#define PCL711_MODE_SOFTTRIG (1 << 0) +#define PCL711_MODE_EXT (2 << 0) +#define PCL711_MODE_EXT_IRQ (3 << 0) +#define PCL711_MODE_PACER (4 << 0) +#define PCL711_MODE_PACER_IRQ (6 << 0) +#define PCL711_MODE_IRQ(x) (((x) & 0x7) << 4) +#define PCL711_SOFTTRIG_REG 0x0c +#define PCL711_SOFTTRIG (0 << 0) /* any value will work */ +#define PCL711_DO_LSB_REG 0x0d +#define PCL711_DO_MSB_REG 0x0e + +static const struct comedi_lrange range_pcl711b_ai = { + 5, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_acl8112hg_ai = { 12, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01) - } +static const struct comedi_lrange range_acl8112hg_ai = { + 12, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_acl8112dg_ai = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10) - } +static const struct comedi_lrange range_acl8112dg_ai = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; -/* - * flags - */ - -#define PCL711_TIMEOUT 100 -#define PCL711_DRDY 0x10 - -static const int i8253_osc_base = 500; /* 2 Mhz */ - struct pcl711_board { - const char *name; - int is_pcl711b; - int is_8112; - int is_dg; - int n_ranges; int n_aichan; int n_aochan; int maxirq; const struct comedi_lrange *ai_range_type; }; -struct pcl711_private { +static const struct pcl711_board boardtypes[] = { + { + .name = "pcl711", + .n_aichan = 8, + .n_aochan = 1, + .ai_range_type = &range_bipolar5, + }, { + .name = "pcl711b", + .n_aichan = 8, + .n_aochan = 1, + .maxirq = 7, + .ai_range_type = &range_pcl711b_ai, + }, { + .name = "acl8112hg", + .n_aichan = 16, + .n_aochan = 2, + .maxirq = 15, + .ai_range_type = &range_acl8112hg_ai, + }, { + .name = "acl8112dg", + .n_aichan = 16, + .n_aochan = 2, + .maxirq = 15, + .ai_range_type = &range_acl8112dg_ai, + }, +}; - int board; - int adchan; - int ntrig; - int aip[8]; - int mode; +struct pcl711_private { + unsigned int ntrig; unsigned int ao_readback[2]; unsigned int divisor1; unsigned int divisor2; }; +static void pcl711_ai_set_mode(struct comedi_device *dev, unsigned int mode) +{ + /* + * The pcl711b board uses bits in the mode register to select the + * interrupt. The other boards supported by this driver all use + * jumpers on the board. + * + * Enables the interrupt when needed on the pcl711b board. These + * bits do nothing on the other boards. + */ + if (mode == PCL711_MODE_EXT_IRQ || mode == PCL711_MODE_PACER_IRQ) + mode |= PCL711_MODE_IRQ(dev->irq); + + outb(mode, dev->iobase + PCL711_MODE_REG); +} + +static unsigned int pcl711_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inb(dev->iobase + PCL711_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL711_AI_LSB_REG); + + return val & s->maxdata; +} + +static int pcl711_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); + return 0; +} + static irqreturn_t pcl711_interrupt(int irq, void *d) { - int lo, hi; - int data; struct comedi_device *dev = d; - const struct pcl711_board *board = comedi_board(dev); struct pcl711_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int data; if (!dev->attached) { comedi_error(dev, "spurious interrupt"); return IRQ_HANDLED; } - hi = inb(dev->iobase + PCL711_AD_HI); - lo = inb(dev->iobase + PCL711_AD_LO); - outb(0, dev->iobase + PCL711_CLRINTR); - - data = (hi << 8) | lo; + data = pcl711_ai_get_sample(dev, s); - /* FIXME! Nothing else sets ntrig! */ - if (!(--devpriv->ntrig)) { - if (board->is_8112) - outb(1, dev->iobase + PCL711_MODE); - else - outb(0, dev->iobase + PCL711_MODE); + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); - s->async->events |= COMEDI_CB_EOA; + if (comedi_buf_put(s->async, data) == 0) { + s->async->events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + } else { + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + if (s->async->cmd.stop_src == TRIG_COUNT && + !(--devpriv->ntrig)) { + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); + s->async->events |= COMEDI_CB_EOA; + } } comedi_event(dev, s); return IRQ_HANDLED; } -static void pcl711_set_changain(struct comedi_device *dev, int chan) +static void pcl711_set_changain(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chanspec) { - const struct pcl711_board *board = comedi_board(dev); - int chan_register; - - outb(CR_RANGE(chan), dev->iobase + PCL711_GAIN); - - chan_register = CR_CHAN(chan); - - if (board->is_8112) { + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int mux = 0; + + outb(PCL711_AI_GAIN(range), dev->iobase + PCL711_AI_GAIN_REG); + + if (s->n_chan > 8) { + /* Select the correct MPC508A chip */ + if (aref == AREF_DIFF) { + chan &= 0x7; + mux |= PCL711_MUX_DIFF; + } else { + if (chan < 8) + mux |= PCL711_MUX_CS0; + else + mux |= PCL711_MUX_CS1; + } + } + outb(mux | PCL711_MUX_CHAN(chan), dev->iobase + PCL711_MUX_REG); +} - /* - * Set the correct channel. The two channel banks are switched - * using the mask value. - * NB: To use differential channels, you should use - * mask = 0x30, but I haven't written the support for this - * yet. /JJ - */ +static int pcl711_ai_wait_for_eoc(struct comedi_device *dev, + unsigned int timeout) +{ + unsigned int msb; - if (chan_register >= 8) - chan_register = 0x20 | (chan_register & 0x7); - else - chan_register |= 0x10; - } else { - outb(chan_register, dev->iobase + PCL711_MUX); + while (timeout--) { + msb = inb(dev->iobase + PCL711_AI_MSB_REG); + if ((msb & PCL711_AI_MSB_DRDY) == 0) + return 0; + udelay(1); } + return -ETIME; } -static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcl711_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - const struct pcl711_board *board = comedi_board(dev); - int i, n; - int hi, lo; - - pcl711_set_changain(dev, insn->chanspec); - - for (n = 0; n < insn->n; n++) { - /* - * Write the correct mode (software polling) and start polling - * by writing to the trigger register - */ - outb(1, dev->iobase + PCL711_MODE); - - if (!board->is_8112) - outb(0, dev->iobase + PCL711_SOFTTRIG); - - i = PCL711_TIMEOUT; - while (--i) { - hi = inb(dev->iobase + PCL711_AD_HI); - if (!(hi & PCL711_DRDY)) - goto ok; - udelay(1); - } - printk(KERN_ERR "comedi%d: pcl711: A/D timeout\n", dev->minor); - return -ETIME; + int ret; + int i; + + pcl711_set_changain(dev, s, insn->chanspec); -ok: - lo = inb(dev->iobase + PCL711_AD_LO); + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); - data[n] = ((hi & 0xf) << 8) | lo; + for (i = 0; i < insn->n; i++) { + outb(PCL711_SOFTTRIG, dev->iobase + PCL711_SOFTTRIG_REG); + + ret = pcl711_ai_wait_for_eoc(dev, 100); + if (ret) + return ret; + + data[i] = pcl711_ai_get_sample(dev, s); } - return n; + return insn->n; } static int pcl711_ai_cmdtest(struct comedi_device *dev, @@ -292,7 +329,6 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); } else { #define MAX_SPEED 1000 -#define TIMER_BASE 100 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, MAX_SPEED); } @@ -313,11 +349,11 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) { tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->scan_begin_arg, + cmd->flags); if (tmp != cmd->scan_begin_arg) err++; } @@ -331,110 +367,106 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl711_private *devpriv = dev->private; - int timer1, timer2; struct comedi_cmd *cmd = &s->async->cmd; - pcl711_set_changain(dev, cmd->chanlist[0]); + pcl711_set_changain(dev, s, cmd->chanlist[0]); + + if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_arg == 0) { + /* an empty acquisition */ + s->async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); + return 0; + } + devpriv->ntrig = cmd->stop_arg; + } if (cmd->scan_begin_src == TRIG_TIMER) { - /* - * Set timers - * timer chip is an 8253, with timers 1 and 2 - * cascaded - * 0x74 = Select Counter 1 | LSB/MSB | Mode=2 | Binary - * Mode 2 = Rate generator - * - * 0xb4 = Select Counter 2 | LSB/MSB | Mode=2 | Binary - */ - - timer1 = timer2 = 0; - i8253_cascade_ns_to_timer(i8253_osc_base, &timer1, &timer2, - &cmd->scan_begin_arg, - TRIG_ROUND_NEAREST); - - outb(0x74, dev->iobase + PCL711_CTRCTL); - outb(timer1 & 0xff, dev->iobase + PCL711_CTR1); - outb((timer1 >> 8) & 0xff, dev->iobase + PCL711_CTR1); - outb(0xb4, dev->iobase + PCL711_CTRCTL); - outb(timer2 & 0xff, dev->iobase + PCL711_CTR2); - outb((timer2 >> 8) & 0xff, dev->iobase + PCL711_CTR2); - - /* clear pending interrupts (just in case) */ - outb(0, dev->iobase + PCL711_CLRINTR); - - /* - * Set mode to IRQ transfer - */ - outb(devpriv->mode | 6, dev->iobase + PCL711_MODE); + i8254_load(dev->iobase + PCL711_TIMER_BASE, 0, + 1, devpriv->divisor1, I8254_MODE2 | I8254_BINARY); + i8254_load(dev->iobase + PCL711_TIMER_BASE, 0, + 2, devpriv->divisor2, I8254_MODE2 | I8254_BINARY); + + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); + + pcl711_ai_set_mode(dev, PCL711_MODE_PACER_IRQ); } else { - /* external trigger */ - outb(devpriv->mode | 3, dev->iobase + PCL711_MODE); + pcl711_ai_set_mode(dev, PCL711_MODE_EXT_IRQ); } return 0; } -/* - analog output -*/ -static int pcl711_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl711_ao_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) { - struct pcl711_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); + outb(val & 0xff, dev->iobase + PCL711_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + PCL711_AO_MSB_REG(chan)); +} - for (n = 0; n < insn->n; n++) { - outb((data[n] & 0xff), - dev->iobase + (chan ? PCL711_DA1_LO : PCL711_DA0_LO)); - outb((data[n] >> 8), - dev->iobase + (chan ? PCL711_DA1_HI : PCL711_DA0_HI)); +static int pcl711_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl711_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int i; - devpriv->ao_readback[chan] = data[n]; + for (i = 0; i < insn->n; i++) { + val = data[i]; + pcl711_ao_write(dev, chan, val); } + devpriv->ao_readback[chan] = val; - return n; + return insn->n; } static int pcl711_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct pcl711_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - return n; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + return insn->n; } -/* Digital port read - Untested on 8112 */ static int pcl711_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - data[1] = inb(dev->iobase + PCL711_DI_LO) | - (inb(dev->iobase + PCL711_DI_HI) << 8); + unsigned int val; + + val = inb(dev->iobase + PCL711_DI_LSB_REG); + val |= (inb(dev->iobase + PCL711_DI_MSB_REG) << 8); + + data[1] = val; return insn->n; } -/* Digital port write - Untested on 8112 */ static int pcl711_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x00ff) + outb(s->state & 0xff, dev->iobase + PCL711_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), dev->iobase + PCL711_DO_MSB_REG); } - if (data[0] & 0x00ff) - outb(s->state & 0xff, dev->iobase + PCL711_DO_LO); - if (data[0] & 0xff00) - outb((s->state >> 8), dev->iobase + PCL711_DO_HI); data[1] = s->state; @@ -445,112 +477,82 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl711_board *board = comedi_board(dev); struct pcl711_private *devpriv; - int ret; - unsigned int irq; struct comedi_subdevice *s; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = comedi_request_region(dev, it->options[0], PCL711_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - /* grab our IRQ */ - irq = it->options[1]; - if (irq > board->maxirq) { - printk(KERN_ERR "irq out of range\n"); - return -EINVAL; - } - if (irq) { - if (request_irq(irq, pcl711_interrupt, 0, dev->board_name, - dev)) { - printk(KERN_ERR "unable to allocate irq %u\n", irq); - return -EINVAL; - } else { - printk(KERN_INFO "( irq = %u )\n", irq); - } + if (it->options[1] && it->options[1] <= board->maxirq) { + ret = request_irq(it->options[1], pcl711_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - dev->irq = irq; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* AI subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = board->n_aichan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->range_table = board->ai_range_type; - s->insn_read = pcl711_ai_insn; - if (irq) { + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + if (board->n_aichan > 8) + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan; + s->maxdata = 0xfff; + s->range_table = board->ai_range_type; + s->insn_read = pcl711_ai_insn_read; + if (dev->irq) { dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmdtest = pcl711_ai_cmdtest; - s->do_cmd = pcl711_ai_cmd; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; + s->do_cmdtest = pcl711_ai_cmdtest; + s->do_cmd = pcl711_ai_cmd; + s->cancel = pcl711_ai_cancel; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* AO subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_aochan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->range_table = &range_bipolar5; - s->insn_write = pcl711_ao_insn; - s->insn_read = pcl711_ao_insn_read; - + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_aochan; + s->maxdata = 0xfff; + s->range_table = &range_bipolar5; + s->insn_write = pcl711_ao_insn_write; + s->insn_read = pcl711_ao_insn_read; + + /* Digital Input subdevice */ s = &dev->subdevices[2]; - /* 16-bit digital input */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 16; - s->range_table = &range_digital; - s->insn_bits = pcl711_di_insn_bits; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl711_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - /* 16-bit digital out */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 16; - s->range_table = &range_digital; - s->state = 0; - s->insn_bits = pcl711_do_insn_bits; - - /* - this is the "base value" for the mode register, which is - used for the irq on the PCL711 - */ - if (board->is_pcl711b) - devpriv->mode = (dev->irq << 4); + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl711_do_insn_bits; /* clear DAC */ - outb(0, dev->iobase + PCL711_DA0_LO); - outb(0, dev->iobase + PCL711_DA0_HI); - outb(0, dev->iobase + PCL711_DA1_LO); - outb(0, dev->iobase + PCL711_DA1_HI); - - printk(KERN_INFO "\n"); + pcl711_ao_write(dev, 0, 0x0); + pcl711_ao_write(dev, 1, 0x0); return 0; } -static const struct pcl711_board boardtypes[] = { - { "pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5 }, - { "pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai }, - { "acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai }, - { "acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai }, -}; - static struct comedi_driver pcl711_driver = { .driver_name = "pcl711", .module = THIS_MODULE, @@ -563,5 +565,5 @@ static struct comedi_driver pcl711_driver = { module_comedi_driver(pcl711_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for PCL-711 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index a4d0bcc31e52..cf9568ee46e4 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -1,230 +1,356 @@ /* - comedi/drivers/pcl726.c - - hardware driver for Advantech cards: - card: PCL-726, PCL-727, PCL-728 - driver: pcl726, pcl727, pcl728 - and for ADLink cards: - card: ACL-6126, ACL-6128 - driver: acl6126, acl6128 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.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, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: pcl726 -Description: Advantech PCL-726 & compatibles -Author: ds -Status: untested -Devices: [Advantech] PCL-726 (pcl726), PCL-727 (pcl727), PCL-728 (pcl728), - [ADLink] ACL-6126 (acl6126), ACL-6128 (acl6128) - -Interrupts are not supported. - - Options for PCL-726: - [0] - IO Base - [2]...[7] - D/A output range for channel 1-6: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA, 5: unknown (external reference) - - Options for PCL-727: - [0] - IO Base - [2]...[13] - D/A output range for channel 1-12: - 0: 0-5V, 1: 0-10V, 2: +/-5V, - 3: 4-20mA - - Options for PCL-728 and ACL-6128: - [0] - IO Base - [2], [3] - D/A output range for channel 1 and 2: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA, 5: 0-20mA - - Options for ACL-6126: - [0] - IO Base - [1] - IRQ (0=disable, 3, 5, 6, 7, 9, 10, 11, 12, 15) (currently ignored) - [2]...[7] - D/A output range for channel 1-6: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA -*/ + * pcl726.c + * Comedi driver for 6/12-Channel D/A Output and DIO cards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.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, 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. + */ /* - Thanks to Circuit Specialists for having programming info (!) on - their web page. (http://www.cir.com/) -*/ + * Driver: pcl726 + * Description: Advantech PCL-726 & compatibles + * Author: David A. Schleef <ds@schleef.org> + * Status: untested + * Devices: (Advantech) PCL-726 [pcl726] + * (Advantech) PCL-727 [pcl727] + * (Advantech) PCL-728 [pcl728] + * (ADLink) ACL-6126 [acl6126] + * (ADLink) ACL-6128 [acl6128] + * + * Configuration Options: + * [0] - IO Base + * [1] - IRQ (ACL-6126 only) + * [2] - D/A output range for channel 0 + * [3] - D/A output range for channel 1 + * + * Boards with > 2 analog output channels: + * [4] - D/A output range for channel 2 + * [5] - D/A output range for channel 3 + * [6] - D/A output range for channel 4 + * [7] - D/A output range for channel 5 + * + * Boards with > 6 analog output channels: + * [8] - D/A output range for channel 6 + * [9] - D/A output range for channel 7 + * [10] - D/A output range for channel 8 + * [11] - D/A output range for channel 9 + * [12] - D/A output range for channel 10 + * [13] - D/A output range for channel 11 + * + * For PCL-726 the D/A output ranges are: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA, 5: unknown + * + * For PCL-727: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: 4-20mA + * + * For PCL-728 and ACL-6128: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA, 5: 0-20mA + * + * For ACL-6126: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA + */ #include <linux/module.h> -#include "../comedidev.h" - -#undef ACL6126_IRQ /* no interrupt support (yet) */ +#include <linux/interrupt.h> -#define PCL726_SIZE 16 -#define PCL727_SIZE 32 -#define PCL728_SIZE 8 +#include "../comedidev.h" -#define PCL726_DAC0_HI 0 -#define PCL726_DAC0_LO 1 +#include "comedi_fc.h" -#define PCL726_DO_HI 12 -#define PCL726_DO_LO 13 -#define PCL726_DI_HI 14 -#define PCL726_DI_LO 15 +#define PCL726_AO_MSB_REG(x) (0x00 + ((x) * 2)) +#define PCL726_AO_LSB_REG(x) (0x01 + ((x) * 2)) +#define PCL726_DO_MSB_REG 0x0c +#define PCL726_DO_LSB_REG 0x0d +#define PCL726_DI_MSB_REG 0x0e +#define PCL726_DI_LSB_REG 0x0f -#define PCL727_DO_HI 24 -#define PCL727_DO_LO 25 -#define PCL727_DI_HI 0 -#define PCL727_DI_LO 1 +#define PCL727_DI_MSB_REG 0x00 +#define PCL727_DI_LSB_REG 0x01 +#define PCL727_DO_MSB_REG 0x18 +#define PCL727_DO_LSB_REG 0x19 static const struct comedi_lrange *const rangelist_726[] = { - &range_unipolar5, &range_unipolar10, - &range_bipolar5, &range_bipolar10, - &range_4_20mA, &range_unknown + &range_unipolar5, + &range_unipolar10, + &range_bipolar5, + &range_bipolar10, + &range_4_20mA, + &range_unknown }; static const struct comedi_lrange *const rangelist_727[] = { - &range_unipolar5, &range_unipolar10, + &range_unipolar5, + &range_unipolar10, &range_bipolar5, &range_4_20mA }; static const struct comedi_lrange *const rangelist_728[] = { - &range_unipolar5, &range_unipolar10, - &range_bipolar5, &range_bipolar10, - &range_4_20mA, &range_0_20mA + &range_unipolar5, + &range_unipolar10, + &range_bipolar5, + &range_bipolar10, + &range_4_20mA, + &range_0_20mA }; struct pcl726_board { - - const char *name; /* driver name */ - int n_aochan; /* num of D/A chans */ - int num_of_ranges; /* num of ranges */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int io_range; /* len of IO space */ - char have_dio; /* 1=card have DI/DO ports */ - int di_hi; /* ports for DI/DO operations */ - int di_lo; - int do_hi; - int do_lo; - const struct comedi_lrange *const *range_type_list; - /* list of supported ranges */ + const char *name; + unsigned long io_len; + unsigned int irq_mask; + const struct comedi_lrange *const *ao_ranges; + int ao_num_ranges; + int ao_nchan; + unsigned int have_dio:1; + unsigned int is_pcl727:1; }; -static const struct pcl726_board boardtypes[] = { - {"pcl726", 6, 6, 0x0000, PCL726_SIZE, 1, - PCL726_DI_HI, PCL726_DI_LO, PCL726_DO_HI, PCL726_DO_LO, - &rangelist_726[0],}, - {"pcl727", 12, 4, 0x0000, PCL727_SIZE, 1, - PCL727_DI_HI, PCL727_DI_LO, PCL727_DO_HI, PCL727_DO_LO, - &rangelist_727[0],}, - {"pcl728", 2, 6, 0x0000, PCL728_SIZE, 0, - 0, 0, 0, 0, - &rangelist_728[0],}, - {"acl6126", 6, 5, 0x96e8, PCL726_SIZE, 1, - PCL726_DI_HI, PCL726_DI_LO, PCL726_DO_HI, PCL726_DO_LO, - &rangelist_726[0],}, - {"acl6128", 2, 6, 0x0000, PCL728_SIZE, 0, - 0, 0, 0, 0, - &rangelist_728[0],}, +static const struct pcl726_board pcl726_boards[] = { + { + .name = "pcl726", + .io_len = 0x10, + .ao_ranges = &rangelist_726[0], + .ao_num_ranges = ARRAY_SIZE(rangelist_726), + .ao_nchan = 6, + .have_dio = 1, + }, { + .name = "pcl727", + .io_len = 0x20, + .ao_ranges = &rangelist_727[0], + .ao_num_ranges = ARRAY_SIZE(rangelist_727), + .ao_nchan = 12, + .have_dio = 1, + .is_pcl727 = 1, + }, { + .name = "pcl728", + .io_len = 0x08, + .ao_num_ranges = ARRAY_SIZE(rangelist_728), + .ao_ranges = &rangelist_728[0], + .ao_nchan = 2, + }, { + .name = "acl6126", + .io_len = 0x10, + .irq_mask = 0x96e8, + .ao_num_ranges = ARRAY_SIZE(rangelist_726), + .ao_ranges = &rangelist_726[0], + .ao_nchan = 6, + .have_dio = 1, + }, { + .name = "acl6128", + .io_len = 0x08, + .ao_num_ranges = ARRAY_SIZE(rangelist_728), + .ao_ranges = &rangelist_728[0], + .ao_nchan = 2, + }, }; struct pcl726_private { - - int bipolar[12]; const struct comedi_lrange *rangelist[12]; unsigned int ao_readback[12]; + unsigned int cmd_running:1; }; -static int pcl726_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcl726_intr_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = 0; + return insn->n; +} + +static int pcl726_intr_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1); + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: ignored */ + + if (err) + return 4; + + return 0; +} + +static int pcl726_intr_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl726_private *devpriv = dev->private; + + devpriv->cmd_running = 1; + + return 0; +} + +static int pcl726_intr_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl726_private *devpriv = dev->private; - int hi, lo; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { - lo = data[n] & 0xff; - hi = (data[n] >> 8) & 0xf; - if (devpriv->bipolar[chan]) - hi ^= 0x8; - /* - * the programming info did not say which order - * to write bytes. switch the order of the next - * two lines if you get glitches. - */ - outb(hi, dev->iobase + PCL726_DAC0_HI + 2 * chan); - outb(lo, dev->iobase + PCL726_DAC0_LO + 2 * chan); - devpriv->ao_readback[chan] = data[n]; + + devpriv->cmd_running = 0; + + return 0; +} + +static irqreturn_t pcl726_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct pcl726_private *devpriv = dev->private; + + if (devpriv->cmd_running) { + pcl726_intr_cancel(dev, s); + + comedi_buf_put(s->async, 0); + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + comedi_event(dev, s); } - return n; + return IRQ_HANDLED; +} + +static int pcl726_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl726_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + devpriv->ao_readback[chan] = val; + + /* bipolar data to the DAC is two's complement */ + if (comedi_chan_range_is_bipolar(s, chan, range)) + val = comedi_offset_munge(s, val); + + /* order is important, MSB then LSB */ + outb((val >> 8) & 0xff, dev->iobase + PCL726_AO_MSB_REG(chan)); + outb(val & 0xff, dev->iobase + PCL726_AO_LSB_REG(chan)); + } + + return insn->n; } static int pcl726_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct pcl726_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int n; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; - return n; + return insn->n; } static int pcl726_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct pcl726_board *board = comedi_board(dev); + unsigned int val; - data[1] = inb(dev->iobase + board->di_lo) | - (inb(dev->iobase + board->di_hi) << 8); + if (board->is_pcl727) { + val = inb(dev->iobase + PCL727_DI_LSB_REG); + val |= (inb(dev->iobase + PCL727_DI_MSB_REG) << 8); + } else { + val = inb(dev->iobase + PCL726_DI_LSB_REG); + val |= (inb(dev->iobase + PCL726_DI_MSB_REG) << 8); + } + + data[1] = val; return insn->n; } static int pcl726_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct pcl726_board *board = comedi_board(dev); - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + unsigned long io = dev->iobase; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (board->is_pcl727) { + if (mask & 0x00ff) + outb(s->state & 0xff, io + PCL727_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), io + PCL727_DO_MSB_REG); + } else { + if (mask & 0x00ff) + outb(s->state & 0xff, io + PCL726_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), io + PCL726_DO_MSB_REG); + } } - if (data[1] & 0x00ff) - outb(s->state & 0xff, dev->iobase + board->do_lo); - if (data[1] & 0xff00) - outb((s->state >> 8), dev->iobase + board->do_hi); data[1] = s->state; return insn->n; } -static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pcl726_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { const struct pcl726_board *board = comedi_board(dev); struct pcl726_private *devpriv; struct comedi_subdevice *s; - int ret, i; -#ifdef ACL6126_IRQ - unsigned int irq; -#endif + int subdev; + int ret; + int i; - ret = comedi_request_region(dev, it->options[0], board->io_range); + ret = comedi_request_region(dev, it->options[0], board->io_len); if (ret) return ret; @@ -232,97 +358,81 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (!devpriv) return -ENOMEM; - for (i = 0; i < 12; i++) { - devpriv->bipolar[i] = 0; - devpriv->rangelist[i] = &range_unknown; - } - -#ifdef ACL6126_IRQ - irq = 0; - if (boardtypes[board].IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - devpriv->first_chan = 2; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & boardtypes[board].IRQbits) == 0) { - printk(KERN_WARNING - ", IRQ %d is out of allowed range," - " DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq(irq, interrupt_pcl818, 0, - dev->board_name, dev)) { - printk(KERN_WARNING - ", unable to allocate IRQ %d," - " DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(", irq=%d", irq); - } - } + /* + * Hook up the external trigger source interrupt only if the + * user config option is valid and the board supports interrupts. + */ + if (it->options[1] && (board->irq_mask & (1 << it->options[1]))) { + ret = request_irq(it->options[1], pcl726_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + /* External trigger source is from Pin-17 of CN3 */ + dev->irq = it->options[1]; } } - dev->irq = irq; -#endif + /* setup the per-channel analog output range_table_list */ + for (i = 0; i < 12; i++) { + unsigned int opt = it->options[2 + i]; - printk("\n"); + if (opt < board->ao_num_ranges && i < board->ao_nchan) + devpriv->rangelist[i] = board->ao_ranges[opt]; + else + devpriv->rangelist[i] = &range_unknown; + } - ret = comedi_alloc_subdevices(dev, 3); + subdev = board->have_dio ? 3 : 1; + if (dev->irq) + subdev++; + ret = comedi_alloc_subdevices(dev, subdev); if (ret) return ret; - s = &dev->subdevices[0]; - /* ao */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->insn_write = pcl726_ao_insn; - s->insn_read = pcl726_ao_insn_read; - s->range_table_list = devpriv->rangelist; - for (i = 0; i < board->n_aochan; i++) { - int j; - - j = it->options[2 + 1]; - if ((j < 0) || (j >= board->num_of_ranges)) { - printk - ("Invalid range for channel %d! Must be 0<=%d<%d\n", - i, j, board->num_of_ranges - 1); - j = 0; - } - devpriv->rangelist[i] = board->range_type_list[j]; - if (devpriv->rangelist[i]->range[0].min == - -devpriv->rangelist[i]->range[0].max) - devpriv->bipolar[i] = 1; /* bipolar range */ - } + subdev = 0; - s = &dev->subdevices[1]; - /* di */ - if (!board->have_dio) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 1; - s->insn_bits = pcl726_di_insn_bits; - s->range_table = &range_digital; + /* Analog Output subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->ao_nchan; + s->maxdata = 0x0fff; + s->range_table_list = devpriv->rangelist; + s->insn_write = pcl726_ao_insn_write; + s->insn_read = pcl726_ao_insn_read; + + if (board->have_dio) { + /* Digital Input subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->insn_bits = pcl726_di_insn_bits; + s->range_table = &range_digital; + + /* Digital Output subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->insn_bits = pcl726_do_insn_bits; + s->range_table = &range_digital; } - s = &dev->subdevices[2]; - /* do */ - if (!board->have_dio) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 1; - s->insn_bits = pcl726_do_insn_bits; - s->range_table = &range_digital; + if (dev->irq) { + /* Digial Input subdevice - Interrupt support */ + s = &dev->subdevices[subdev++]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl726_intr_insn_bits; + s->do_cmdtest = pcl726_intr_cmdtest; + s->do_cmd = pcl726_intr_cmd; + s->cancel = pcl726_intr_cancel; } return 0; @@ -333,12 +443,12 @@ static struct comedi_driver pcl726_driver = { .module = THIS_MODULE, .attach = pcl726_attach, .detach = comedi_legacy_detach, - .board_name = &boardtypes[0].name, - .num_names = ARRAY_SIZE(boardtypes), + .board_name = &pcl726_boards[0].name, + .num_names = ARRAY_SIZE(pcl726_boards), .offset = sizeof(struct pcl726_board), }; module_comedi_driver(pcl726_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Advantech PCL-726 & compatibles"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index 2a659f23ecda..d041b714db29 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -167,20 +167,17 @@ static int pcl730_do_insn_bits(struct comedi_device *dev, unsigned int *data) { unsigned long reg = (unsigned long)s->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; + unsigned int mask; + mask = comedi_dio_update_state(s, data); if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - if (mask & 0x00ff) outb(s->state & 0xff, dev->iobase + reg); - if ((mask & 0xff00) && (s->n_chan > 8)) + if ((mask & 0xff00) & (s->n_chan > 8)) outb((s->state >> 8) & 0xff, dev->iobase + reg + 1); - if ((mask & 0xff0000) && (s->n_chan > 16)) + if ((mask & 0xff0000) & (s->n_chan > 16)) outb((s->state >> 16) & 0xff, dev->iobase + reg + 2); - if ((mask & 0xff000000) && (s->n_chan > 24)) + if ((mask & 0xff000000) & (s->n_chan > 24)) outb((s->state >> 24) & 0xff, dev->iobase + reg + 3); } diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 03a098900d34..03315abcca19 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -355,7 +355,6 @@ struct pcl812_private { unsigned int ai_n_chan; /* how many channels is measured */ unsigned int ai_flags; /* flaglist */ unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ unsigned int ai_is16b; /* =1 we have 16 bit card */ unsigned long dmabuf[2]; /* PTR to DMA buf */ unsigned int dmapages[2]; /* how many pages we have allocated */ @@ -509,19 +508,16 @@ static int pcl812_di_insn_bits(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static int pcl812_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + if (comedi_dio_update_state(s, data)) { outb(s->state & 0xff, dev->iobase + PCL812_DO_LO); outb((s->state >> 8), dev->iobase + PCL812_DO_HI); } + data[1] = s->state; return insn->n; @@ -592,9 +588,9 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(board->i8254_osc_base, + &divisor1, &divisor2, + &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < board->ai_ns_min) cmd->convert_arg = board->ai_ns_min; if (tmp != cmd->convert_arg) @@ -640,8 +636,7 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) cmd->convert_arg = board->ai_ns_min; i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1, &divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + &cmd->convert_arg, cmd->flags); } start_pacer(dev, -1, 0, 0); /* stop pacer */ @@ -665,7 +660,6 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_flags = cmd->flags; devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; if (cmd->stop_src == TRIG_COUNT) { devpriv->ai_scans = cmd->stop_arg; devpriv->ai_neverending = 0; @@ -835,7 +829,8 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) ============================================================================== */ static void transfer_from_dma_buf(struct comedi_device *dev, - struct comedi_subdevice *s, short *ptr, + struct comedi_subdevice *s, + unsigned short *ptr, unsigned int bufptr, unsigned int len) { struct pcl812_private *devpriv = dev->private; @@ -873,9 +868,9 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) struct comedi_subdevice *s = &dev->subdevices[0]; unsigned long dma_flags; int len, bufptr; - short *ptr; + unsigned short *ptr; - ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf]; + ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - devpriv->ai_poll_ptr; @@ -1443,40 +1438,40 @@ static void pcl812_detach(struct comedi_device *dev) static const struct pcl812_board boardtypes[] = { {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff, - 33000, 500, &range_bipolar10, &range_unipolar5, + 33000, I8254_OSC_BASE_2MHZ, &range_bipolar10, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 33000, 500, &range_pcl812pg_ai, &range_unipolar5, + 33000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 10000, 500, &range_pcl812pg_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112dg_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112hg_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, 500, &range_pcl813b_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, &range_unipolar5, 0x000c, 0x00, PCLx1x_IORANGE, 0}, {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, - 10000, 500, &range_pcl813b_ai, NULL, + 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, NULL, 0x000c, 0x00, PCLx1x_IORANGE, 0}, {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, 500, &range_a821pgh_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_a821pgh_ai, &range_unipolar5, 0x000c, 0x00, PCLx1x_IORANGE, 0}, {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112dg_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112hg_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, 500, &range_acl8112dg_ai, &range_unipolar5, + 8000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, 500, &range_acl8112hg_ai, &range_unipolar5, + 8000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, 0, 0, &range_pcl813b_ai, NULL, @@ -1491,10 +1486,10 @@ static const struct pcl812_board boardtypes[] = { 0, 0, &range_iso813_1_ai, NULL, 0x0000, 0x00, PCLx1x_IORANGE, 0}, {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, 500, &range_pcl813b2_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, 500, &range_pcl813b2_ai, &range_unipolar5, + 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5, 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, }; diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index f03134962596..ab9d2bd26a20 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -229,7 +229,7 @@ static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) struct comedi_device *dev = d; struct pcl816_private *devpriv = dev->private; struct comedi_subdevice *s = &dev->subdevices[0]; - int low, hi; + unsigned char low, hi; int timeout = 50; /* wait max 50us */ while (timeout--) { @@ -281,7 +281,8 @@ static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) analog input dma mode 1 & 3, 816 cards */ static void transfer_from_dma_buf(struct comedi_device *dev, - struct comedi_subdevice *s, short *ptr, + struct comedi_subdevice *s, + unsigned short *ptr, unsigned int bufptr, unsigned int len) { struct pcl816_private *devpriv = dev->private; @@ -324,7 +325,7 @@ static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) struct comedi_subdevice *s = &dev->subdevices[0]; int len, bufptr, this_dma_buf; unsigned long dma_flags; - short *ptr; + unsigned short *ptr; disable_dma(devpriv->dma); this_dma_buf = devpriv->next_dma_buf; @@ -352,7 +353,7 @@ static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) devpriv->dma_runs_to_end--; outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - ptr = (short *)devpriv->dmabuf[this_dma_buf]; + ptr = (unsigned short *)devpriv->dmabuf[this_dma_buf]; len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr; bufptr = devpriv->ai_poll_ptr; @@ -481,8 +482,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, tmp = cmd->convert_arg; i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1, &divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < board->ai_ns_min) cmd->convert_arg = board->ai_ns_min; if (tmp != cmd->convert_arg) @@ -528,9 +528,9 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (cmd->convert_arg < board->ai_ns_min) cmd->convert_arg = board->ai_ns_min; - i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(board->i8254_osc_base, + &divisor1, &divisor2, + &cmd->convert_arg, cmd->flags); /* PCL816 crash if any divisor is set to 1 */ if (divisor1 == 1) { @@ -666,7 +666,8 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) } transfer_from_dma_buf(dev, s, - (short *)devpriv->dmabuf[devpriv->next_dma_buf], + (unsigned short *)devpriv->dmabuf[devpriv-> + next_dma_buf], devpriv->ai_poll_ptr, top2); devpriv->ai_poll_ptr = top1; /* new buffer position */ @@ -1105,7 +1106,7 @@ static const struct pcl816_board boardtypes[] = { 0xffff, /* D/A maxdata */ 1024, 1, /* ao chan list */ - 100}, + I8254_OSC_BASE_10MHZ}, {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, &range_pcl816, PCLx1x_RANGE, 0x00fc, @@ -1114,7 +1115,7 @@ static const struct pcl816_board boardtypes[] = { 0x3fff, 1024, 1, - 100}, + I8254_OSC_BASE_10MHZ}, }; static struct comedi_driver pcl816_driver = { diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index a52ba82ff0e4..9e4d7e860509 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -289,7 +289,6 @@ struct pcl818_private { unsigned int *ai_chanlist; /* actaul chanlist */ unsigned int ai_flags; /* flaglist */ unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ unsigned int ai_timer1; /* timers */ unsigned int ai_timer2; struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ @@ -418,21 +417,15 @@ static int pcl818_di_insn_bits(struct comedi_device *dev, return insn->n; } -/* -============================================================================== - DIGITAL OUTPUT MODE0, 818 cards - - only one sample per call is supported -*/ static int pcl818_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - outb(s->state & 0xff, dev->iobase + PCL818_DO_LO); - outb((s->state >> 8), dev->iobase + PCL818_DO_HI); + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL818_DO_LO); + outb((s->state >> 8), dev->iobase + PCL818_DO_HI); + } data[1] = s->state; @@ -449,7 +442,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) struct comedi_device *dev = d; struct pcl818_private *devpriv = dev->private; struct comedi_subdevice *s = &dev->subdevices[0]; - int low; + unsigned char low; int timeout = 50; /* wait max 50us */ while (timeout--) { @@ -511,7 +504,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) struct comedi_subdevice *s = &dev->subdevices[0]; int i, len, bufptr; unsigned long flags; - short *ptr; + unsigned short *ptr; disable_dma(devpriv->dma); devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; @@ -534,7 +527,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) devpriv->dma_runs_to_end--; outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; + ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; len = devpriv->hwdmasize[0] >> 1; bufptr = 0; @@ -588,7 +581,8 @@ static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) struct comedi_device *dev = d; struct pcl818_private *devpriv = dev->private; struct comedi_subdevice *s = &dev->subdevices[0]; - int i, len, lo; + int i, len; + unsigned char lo; outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ @@ -806,8 +800,9 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, devpriv->neverending_ai = 1; /* well, user want neverending */ if (mode == 1) { - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, + i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, + &divisor1, &divisor2, + &cmd->convert_arg, TRIG_ROUND_NEAREST); if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */ divisor1 = 2; @@ -1040,9 +1035,9 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, + &divisor1, &divisor2, + &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < board->ns_min) cmd->convert_arg = board->ns_min; if (tmp != cmd->convert_arg) @@ -1077,7 +1072,6 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_chanlist = cmd->chanlist; devpriv->ai_flags = cmd->flags; devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; devpriv->ai_timer1 = 0; devpriv->ai_timer2 = 0; @@ -1438,9 +1432,9 @@ no_dma: /* select 1/10MHz oscilator */ if ((it->options[3] == 0) || (it->options[3] == 10)) - devpriv->i8253_osc_base = 100; + devpriv->i8253_osc_base = I8254_OSC_BASE_10MHZ; else - devpriv->i8253_osc_base = 1000; + devpriv->i8253_osc_base = I8254_OSC_BASE_1MHZ; /* max sampling speed */ devpriv->ns_min = board->ns_min; diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index 423f23676d26..fe482fdd512e 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -75,12 +75,6 @@ static int pcmad_ai_wait_for_eoc(struct comedi_device *dev, return -ETIME; } -static bool pcmad_range_is_bipolar(struct comedi_subdevice *s, - unsigned int range) -{ - return s->range_table->range[range].min < 0; -} - static int pcmad_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -106,7 +100,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev, if (s->maxdata == 0x0fff) val >>= 4; - if (pcmad_range_is_bipolar(s, range)) { + if (comedi_range_is_bipolar(s, range)) { /* munge the two's complement value */ val ^= ((s->maxdata + 1) >> 1); } diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 574443df42da..14cee3ac92c5 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -553,12 +553,11 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d) val |= (1U << n); } /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *)&val)[0]) + if (comedi_buf_put(s->async, val) && comedi_buf_put (s->async, - ((short *) - &val)[1])) { + val >> 16)) { s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); } else { /* Overflow! Stop acquisition!! */ @@ -846,7 +845,7 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec); unsigned char command_byte = 0; unsigned iooffset = 0; - short sample, adc_adjust = 0; + unsigned short sample, adc_adjust = 0; if (chan > 7) chan -= 8, iooffset = 4; /* diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index 67e2bb1d66f0..954fa96a50ac 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -315,8 +315,8 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev, } /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *)&val)[0]) && - comedi_buf_put(s->async, ((short *)&val)[1])) { + if (comedi_buf_put(s->async, val) && + comedi_buf_put(s->async, val >> 16)) { s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); } else { /* Overflow! Stop acquisition!! */ diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 9775d3622a62..96a46954b3c0 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -208,8 +208,7 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) case buffer: while (!((status = inb(dev->iobase + DAQP_STATUS)) & DAQP_STATUS_FIFO_EMPTY)) { - - short data; + unsigned short data; if (status & DAQP_STATUS_DATA_LOST) { s->async->events |= @@ -690,18 +689,12 @@ static int daqp_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct daqp_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; if (devpriv->stop) return -EIO; - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) outb(s->state, dev->iobase + DAQP_DIGITAL_IO); - } data[1] = s->state; diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 93c980c62a23..0ae2d6175471 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -602,7 +602,7 @@ static int rtd_ai_rinsn(struct comedi_device *dev, /* convert n samples */ for (n = 0; n < insn->n; n++) { - s16 d; + unsigned short d; /* trigger conversion */ writew(0, devpriv->las0 + LAS0_ADC); @@ -621,9 +621,8 @@ static int rtd_ai_rinsn(struct comedi_device *dev, d = d >> 3; /* low 3 bits are marker lines */ if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar, 0)) /* convert to comedi unsigned data */ - data[n] = d + 2048; - else - data[n] = d; + d = comedi_offset_munge(s, d); + data[n] = d & s->maxdata; } /* return the number of samples read/written */ @@ -643,8 +642,7 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, int ii; for (ii = 0; ii < count; ii++) { - short sample; - s16 d; + unsigned short d; if (0 == devpriv->ai_count) { /* done */ d = readw(devpriv->las1 + LAS1_ADC_FIFO); @@ -654,13 +652,12 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, d = readw(devpriv->las1 + LAS1_ADC_FIFO); d = d >> 3; /* low 3 bits are marker lines */ if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar, - s->async->cur_chan)) { + s->async->cur_chan)) /* convert to comedi unsigned data */ - sample = d + 2048; - } else - sample = d; + d = comedi_offset_munge(s, d); + d &= s->maxdata; - if (!comedi_buf_put(s->async, sample)) + if (!comedi_buf_put(s->async, d)) return -1; if (devpriv->ai_count > 0) /* < 0, means read forever */ @@ -677,8 +674,7 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s) struct rtd_private *devpriv = dev->private; while (readl(devpriv->las0 + LAS0_ADC) & FS_ADC_NOT_EMPTY) { - short sample; - s16 d = readw(devpriv->las1 + LAS1_ADC_FIFO); + unsigned short d = readw(devpriv->las1 + LAS1_ADC_FIFO); if (0 == devpriv->ai_count) { /* done */ continue; /* read rest */ @@ -686,13 +682,12 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s) d = d >> 3; /* low 3 bits are marker lines */ if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar, - s->async->cur_chan)) { + s->async->cur_chan)) /* convert to comedi unsigned data */ - sample = d + 2048; - } else - sample = d; + d = comedi_offset_munge(s, d); + d &= s->maxdata; - if (!comedi_buf_put(s->async, sample)) + if (!comedi_buf_put(s->async, d)) return -1; if (devpriv->ai_count > 0) /* < 0, means read forever */ @@ -1217,15 +1212,9 @@ static int rtd_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { struct rtd_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) writew(s->state & 0xff, devpriv->las0 + LAS0_DIO0); - } data[1] = readw(devpriv->las0 + LAS0_DIO0) & 0xff; diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index cbb4ba5b852a..e1f3671ac056 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -267,13 +267,7 @@ static int rti800_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int mask = data[0]; - unsigned int bits = data[1]; - - if (mask) { - s->state &= ~mask; - s->state |= (bits & mask); - + if (comedi_dio_update_state(s, data)) { /* Outputs are inverted... */ outb(s->state ^ 0xff, dev->iobase + RTI800_DO); } diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index d629463b85a2..9950f59b1192 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -499,14 +499,11 @@ static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, static int s526_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + REG_DIO); - } data[1] = inw(dev->iobase + REG_DIO) & 0xff; diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index d22b95dcb9bd..d9aba7ce862d 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -1,63 +1,63 @@ /* - comedi/drivers/s626.c - Sensoray s626 Comedi driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - Based on Sensoray Model 626 Linux driver Version 0.2 - Copyright (C) 2002-2004 Sensoray Co., Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi/drivers/s626.c + * Sensoray s626 Comedi driver + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * Based on Sensoray Model 626 Linux driver Version 0.2 + * Copyright (C) 2002-2004 Sensoray Co., Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: s626 -Description: Sensoray 626 driver -Devices: [Sensoray] 626 (s626) -Authors: Gianluca Palli <gpalli@deis.unibo.it>, -Updated: Fri, 15 Feb 2008 10:28:42 +0000 -Status: experimental - -Configuration options: not applicable, uses PCI auto config - -INSN_CONFIG instructions: - analog input: - none - - analog output: - none - - digital channel: - s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels - supported configuration options: - INSN_CONFIG_DIO_QUERY - COMEDI_INPUT - COMEDI_OUTPUT - - encoder: - Every channel must be configured before reading. - - Example code - - insn.insn=INSN_CONFIG; //configuration instruction - insn.n=1; //number of operation (must be 1) - insn.data=&initialvalue; //initial value loaded into encoder - //during configuration - insn.subdev=5; //encoder subdevice - insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel - //to configure - - comedi_do_insn(cf,&insn); //executing configuration -*/ + * Driver: s626 + * Description: Sensoray 626 driver + * Devices: [Sensoray] 626 (s626) + * Authors: Gianluca Palli <gpalli@deis.unibo.it>, + * Updated: Fri, 15 Feb 2008 10:28:42 +0000 + * Status: experimental + + * Configuration options: not applicable, uses PCI auto config + + * INSN_CONFIG instructions: + * analog input: + * none + * + * analog output: + * none + * + * digital channel: + * s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels + * supported configuration options: + * INSN_CONFIG_DIO_QUERY + * COMEDI_INPUT + * COMEDI_OUTPUT + * + * encoder: + * Every channel must be configured before reading. + * + * Example code + * + * insn.insn=INSN_CONFIG; //configuration instruction + * insn.n=1; //number of operation (must be 1) + * insn.data=&initialvalue; //initial value loaded into encoder + * //during configuration + * insn.subdev=5; //encoder subdevice + * insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel + * //to configure + * + * comedi_do_insn(cf,&insn); //executing configuration + */ #include <linux/module.h> #include <linux/delay.h> @@ -71,68 +71,91 @@ INSN_CONFIG instructions: #include "comedi_fc.h" #include "s626.h" -#define PCI_VENDOR_ID_S626 0x1131 -#define PCI_DEVICE_ID_S626 0x7146 -#define PCI_SUBVENDOR_ID_S626 0x6000 -#define PCI_SUBDEVICE_ID_S626 0x0272 +struct s626_buffer_dma { + dma_addr_t physical_base; + void *logical_base; +}; struct s626_private { void __iomem *mmio; - uint8_t ai_cmd_running; /* ai_cmd is running */ - uint8_t ai_continous; /* continous acquisition */ - int ai_sample_count; /* number of samples to acquire */ - unsigned int ai_sample_timer; - /* time between samples in units of the timer */ - int ai_convert_count; /* conversion counter */ - unsigned int ai_convert_timer; - /* time between conversion in units of the timer */ - uint16_t CounterIntEnabs; - /* Counter interrupt enable mask for MISC2 register. */ - uint8_t AdcItems; /* Number of items in ADC poll list. */ - struct bufferDMA RPSBuf; /* DMA buffer used to hold ADC (RPS1) program. */ - struct bufferDMA ANABuf; - /* DMA buffer used to receive ADC data and hold DAC data. */ - uint32_t *pDacWBuf; - /* Pointer to logical adrs of DMA buffer used to hold DAC data. */ - uint16_t Dacpol; /* Image of DAC polarity register. */ - uint8_t TrimSetpoint[12]; /* Images of TrimDAC setpoints */ - /* Charge Enabled (0 or WRMISC2_CHARGE_ENABLE). */ - uint32_t I2CAdrs; - /* I2C device address for onboard EEPROM (board rev dependent). */ - /* short I2Cards; */ + uint8_t ai_cmd_running; /* ai_cmd is running */ + uint8_t ai_continuous; /* continuous acquisition */ + int ai_sample_count; /* number of samples to acquire */ + unsigned int ai_sample_timer; /* time between samples in + * units of the timer */ + int ai_convert_count; /* conversion counter */ + unsigned int ai_convert_timer; /* time between conversion in + * units of the timer */ + uint16_t counter_int_enabs; /* counter interrupt enable mask + * for MISC2 register */ + uint8_t adc_items; /* number of items in ADC poll list */ + struct s626_buffer_dma rps_buf; /* DMA buffer used to hold ADC (RPS1) + * program */ + struct s626_buffer_dma ana_buf; /* DMA buffer used to receive ADC data + * and hold DAC data */ + uint32_t *dac_wbuf; /* pointer to logical adrs of DMA buffer + * used to hold DAC data */ + uint16_t dacpol; /* image of DAC polarity register */ + uint8_t trim_setpoint[12]; /* images of TrimDAC setpoints */ + uint32_t i2c_adrs; /* I2C device address for onboard EEPROM + * (board rev dependent) */ unsigned int ao_readback[S626_DAC_CHANNELS]; }; -/* COUNTER OBJECT ------------------------------------------------ */ -struct enc_private { - /* Pointers to functions that differ for A and B counters: */ - uint16_t(*GetEnable) (struct comedi_device *dev, struct enc_private *); /* Return clock enable. */ - uint16_t(*GetIntSrc) (struct comedi_device *dev, struct enc_private *); /* Return interrupt source. */ - uint16_t(*GetLoadTrig) (struct comedi_device *dev, struct enc_private *); /* Return preload trigger source. */ - uint16_t(*GetMode) (struct comedi_device *dev, struct enc_private *); /* Return standardized operating mode. */ - void (*PulseIndex) (struct comedi_device *dev, struct enc_private *); /* Generate soft index strobe. */ - void (*SetEnable) (struct comedi_device *dev, struct enc_private *, uint16_t enab); /* Program clock enable. */ - void (*SetIntSrc) (struct comedi_device *dev, struct enc_private *, uint16_t IntSource); /* Program interrupt source. */ - void (*SetLoadTrig) (struct comedi_device *dev, struct enc_private *, uint16_t Trig); /* Program preload trigger source. */ - void (*SetMode) (struct comedi_device *dev, struct enc_private *, uint16_t Setup, uint16_t DisableIntSrc); /* Program standardized operating mode. */ - void (*ResetCapFlags) (struct comedi_device *dev, struct enc_private *); /* Reset event capture flags. */ - - uint16_t MyCRA; /* Address of CRA register. */ - uint16_t MyCRB; /* Address of CRB register. */ - uint16_t MyLatchLsw; /* Address of Latch least-significant-word */ - /* register. */ - uint16_t MyEventBits[4]; /* Bit translations for IntSrc -->RDMISC2. */ +/* COUNTER OBJECT ------------------------------------------------ */ +struct s626_enc_info { + /* Pointers to functions that differ for A and B counters: */ + /* Return clock enable. */ + uint16_t(*get_enable)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return interrupt source. */ + uint16_t(*get_int_src)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return preload trigger source. */ + uint16_t(*get_load_trig)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return standardized operating mode. */ + uint16_t(*get_mode)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Generate soft index strobe. */ + void (*pulse_index)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Program clock enable. */ + void (*set_enable)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab); + /* Program interrupt source. */ + void (*set_int_src)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t int_source); + /* Program preload trigger source. */ + void (*set_load_trig)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig); + /* Program standardized operating mode. */ + void (*set_mode)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src); + /* Reset event capture flags. */ + void (*reset_cap_flags)(struct comedi_device *dev, + const struct s626_enc_info *k); + + uint16_t my_cra; /* address of CRA register */ + uint16_t my_crb; /* address of CRB register */ + uint16_t my_latch_lsw; /* address of Latch least-significant-word + * register */ + uint16_t my_event_bits[4]; /* bit translations for IntSrc -->RDMISC2 */ }; -#define encpriv ((struct enc_private *)(dev->subdevices+5)->private) - -/* Counter overflow/index event flag masks for RDMISC2. */ -#define INDXMASK(C) (1 << (((C) > 2) ? ((C) * 2 - 1) : ((C) * 2 + 4))) -#define OVERMASK(C) (1 << (((C) > 2) ? ((C) * 2 + 5) : ((C) * 2 + 10))) -#define EVBITS(C) { 0, OVERMASK(C), INDXMASK(C), OVERMASK(C) | INDXMASK(C) } +/* Counter overflow/index event flag masks for RDMISC2. */ +#define S626_INDXMASK(C) (1 << (((C) > 2) ? ((C) * 2 - 1) : ((C) * 2 + 4))) +#define S626_OVERMASK(C) (1 << (((C) > 2) ? ((C) * 2 + 5) : ((C) * 2 + 10))) +#define S626_EVBITS(C) { 0, S626_OVERMASK(C), S626_INDXMASK(C), \ + S626_OVERMASK(C) | S626_INDXMASK(C) } -/* Translation table to map IntSrc into equivalent RDMISC2 event flag bits. */ -/* static const uint16_t EventBits[][4] = { EVBITS(0), EVBITS(1), EVBITS(2), EVBITS(3), EVBITS(4), EVBITS(5) }; */ +/* + * Translation table to map IntSrc into equivalent RDMISC2 event flag bits. + * static const uint16_t s626_event_bits[][4] = + * { S626_EVBITS(0), S626_EVBITS(1), S626_EVBITS(2), S626_EVBITS(3), + * S626_EVBITS(4), S626_EVBITS(5) }; + */ /* * Enable/disable a function or test status bit(s) that are accessed @@ -144,6 +167,7 @@ static void s626_mc_enable(struct comedi_device *dev, struct s626_private *devpriv = dev->private; unsigned int val = (cmd << 16) | cmd; + mmiowb(); writel(val, devpriv->mmio + reg); } @@ -153,6 +177,7 @@ static void s626_mc_disable(struct comedi_device *dev, struct s626_private *devpriv = dev->private; writel(cmd << 16 , devpriv->mmio + reg); + mmiowb(); } static bool s626_mc_test(struct comedi_device *dev, @@ -166,15 +191,10 @@ static bool s626_mc_test(struct comedi_device *dev, return (val & cmd) ? true : false; } -#define BUGFIX_STREG(REGADRS) (REGADRS - 4) +#define S626_BUGFIX_STREG(REGADRS) ((REGADRS) - 4) -/* Write a time slot control record to TSL2. */ -#define VECTPORT(VECTNUM) (P_TSL2 + ((VECTNUM) << 2)) - -/* Code macros used for constructing I2C command bytes. */ -#define I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) -#define I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) -#define I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) +/* Write a time slot control record to TSL2. */ +#define S626_VECTPORT(VECTNUM) (S626_P_TSL2 + ((VECTNUM) << 2)) static const struct comedi_lrange s626_range_table = { 2, { @@ -183,178 +203,182 @@ static const struct comedi_lrange s626_range_table = { } }; -/* Execute a DEBI transfer. This must be called from within a */ -/* critical section. */ -static void DEBItransfer(struct comedi_device *dev) +/* + * Execute a DEBI transfer. This must be called from within a critical section. + */ +static void s626_debi_transfer(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; /* Initiate upload of shadow RAM to DEBI control register */ - s626_mc_enable(dev, MC2_UPLD_DEBI, P_MC2); + s626_mc_enable(dev, S626_MC2_UPLD_DEBI, S626_P_MC2); /* * Wait for completion of upload from shadow RAM to * DEBI control register. */ - while (!s626_mc_test(dev, MC2_UPLD_DEBI, P_MC2)) + while (!s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) ; /* Wait until DEBI transfer is done */ - while (readl(devpriv->mmio + P_PSR) & PSR_DEBI_S) + while (readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S) ; } -/* Initialize the DEBI interface for all transfers. */ - -static uint16_t DEBIread(struct comedi_device *dev, uint16_t addr) +/* + * Read a value from a gate array register. + */ +static uint16_t s626_debi_read(struct comedi_device *dev, uint16_t addr) { struct s626_private *devpriv = dev->private; /* Set up DEBI control register value in shadow RAM */ - writel(DEBI_CMD_RDWORD | addr, devpriv->mmio + P_DEBICMD); + writel(S626_DEBI_CMD_RDWORD | addr, devpriv->mmio + S626_P_DEBICMD); /* Execute the DEBI transfer. */ - DEBItransfer(dev); + s626_debi_transfer(dev); - return readl(devpriv->mmio + P_DEBIAD); + return readl(devpriv->mmio + S626_P_DEBIAD); } -/* Write a value to a gate array register. */ -static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata) +/* + * Write a value to a gate array register. + */ +static void s626_debi_write(struct comedi_device *dev, uint16_t addr, + uint16_t wdata) { struct s626_private *devpriv = dev->private; /* Set up DEBI control register value in shadow RAM */ - writel(DEBI_CMD_WRWORD | addr, devpriv->mmio + P_DEBICMD); - writel(wdata, devpriv->mmio + P_DEBIAD); + writel(S626_DEBI_CMD_WRWORD | addr, devpriv->mmio + S626_P_DEBICMD); + writel(wdata, devpriv->mmio + S626_P_DEBIAD); /* Execute the DEBI transfer. */ - DEBItransfer(dev); + s626_debi_transfer(dev); } -/* Replace the specified bits in a gate array register. Imports: mask +/* + * Replace the specified bits in a gate array register. Imports: mask * specifies bits that are to be preserved, wdata is new value to be * or'd with the masked original. */ -static void DEBIreplace(struct comedi_device *dev, unsigned int addr, - unsigned int mask, unsigned int wdata) +static void s626_debi_replace(struct comedi_device *dev, unsigned int addr, + unsigned int mask, unsigned int wdata) { struct s626_private *devpriv = dev->private; unsigned int val; addr &= 0xffff; - writel(DEBI_CMD_RDWORD | addr, devpriv->mmio + P_DEBICMD); - DEBItransfer(dev); + writel(S626_DEBI_CMD_RDWORD | addr, devpriv->mmio + S626_P_DEBICMD); + s626_debi_transfer(dev); - writel(DEBI_CMD_WRWORD | addr, devpriv->mmio + P_DEBICMD); - val = readl(devpriv->mmio + P_DEBIAD); + writel(S626_DEBI_CMD_WRWORD | addr, devpriv->mmio + S626_P_DEBICMD); + val = readl(devpriv->mmio + S626_P_DEBIAD); val &= mask; val |= wdata; - writel(val & 0xffff, devpriv->mmio + P_DEBIAD); - DEBItransfer(dev); + writel(val & 0xffff, devpriv->mmio + S626_P_DEBIAD); + s626_debi_transfer(dev); } /* ************** EEPROM ACCESS FUNCTIONS ************** */ -static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val) +static uint32_t s626_i2c_handshake(struct comedi_device *dev, uint32_t val) { struct s626_private *devpriv = dev->private; unsigned int ctrl; /* Write I2C command to I2C Transfer Control shadow register */ - writel(val, devpriv->mmio + P_I2CCTRL); + writel(val, devpriv->mmio + S626_P_I2CCTRL); /* * Upload I2C shadow registers into working registers and * wait for upload confirmation. */ - s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2); - while (!s626_mc_test(dev, MC2_UPLD_IIC, P_MC2)) + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + while (!s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2)) ; /* Wait until I2C bus transfer is finished or an error occurs */ do { - ctrl = readl(devpriv->mmio + P_I2CCTRL); - } while ((ctrl & (I2C_BUSY | I2C_ERR)) == I2C_BUSY); + ctrl = readl(devpriv->mmio + S626_P_I2CCTRL); + } while ((ctrl & (S626_I2C_BUSY | S626_I2C_ERR)) == S626_I2C_BUSY); /* Return non-zero if I2C error occurred */ - return ctrl & I2C_ERR; + return ctrl & S626_I2C_ERR; } -/* Read uint8_t from EEPROM. */ -static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr) +/* Read uint8_t from EEPROM. */ +static uint8_t s626_i2c_read(struct comedi_device *dev, uint8_t addr) { struct s626_private *devpriv = dev->private; - /* Send EEPROM target address. */ - if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CW) - /* Byte2 = I2C command: write to I2C EEPROM device. */ - | I2C_B1(I2C_ATTRSTOP, addr) - /* Byte1 = EEPROM internal target address. */ - | I2C_B0(I2C_ATTRNOP, 0))) { /* Byte0 = Not sent. */ - /* Abort function and declare error if handshake failed. */ + /* + * Send EEPROM target address: + * Byte2 = I2C command: write to I2C EEPROM device. + * Byte1 = EEPROM internal target address. + * Byte0 = Not sent. + */ + if (s626_i2c_handshake(dev, S626_I2C_B2(S626_I2C_ATTRSTART, + devpriv->i2c_adrs) | + S626_I2C_B1(S626_I2C_ATTRSTOP, addr) | + S626_I2C_B0(S626_I2C_ATTRNOP, 0))) + /* Abort function and declare error if handshake failed. */ return 0; - } - /* Execute EEPROM read. */ - if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CR) - - /* Byte2 = I2C */ - /* command: read */ - /* from I2C EEPROM */ - /* device. */ - |I2C_B1(I2C_ATTRSTOP, 0) - /* Byte1 receives */ - /* uint8_t from */ - /* EEPROM. */ - |I2C_B0(I2C_ATTRNOP, 0))) { /* Byte0 = Not sent. */ - - /* Abort function and declare error if handshake failed. */ + /* + * Execute EEPROM read: + * Byte2 = I2C command: read from I2C EEPROM device. + * Byte1 receives uint8_t from EEPROM. + * Byte0 = Not sent. + */ + if (s626_i2c_handshake(dev, S626_I2C_B2(S626_I2C_ATTRSTART, + (devpriv->i2c_adrs | 1)) | + S626_I2C_B1(S626_I2C_ATTRSTOP, 0) | + S626_I2C_B0(S626_I2C_ATTRNOP, 0))) + /* Abort function and declare error if handshake failed. */ return 0; - } - return (readl(devpriv->mmio + P_I2CCTRL) >> 16) & 0xff; + return (readl(devpriv->mmio + S626_P_I2CCTRL) >> 16) & 0xff; } /* *********** DAC FUNCTIONS *********** */ -/* Slot 0 base settings. */ -#define VECT0 (XSD2 | RSD3 | SIB_A2) -/* Slot 0 always shifts in 0xFF and store it to FB_BUFFER2. */ +/* TrimDac LogicalChan-to-PhysicalChan mapping table. */ +static const uint8_t s626_trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 }; -/* TrimDac LogicalChan-to-PhysicalChan mapping table. */ -static uint8_t trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 }; - -/* TrimDac LogicalChan-to-EepromAdrs mapping table. */ -static uint8_t trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 }; +/* TrimDac LogicalChan-to-EepromAdrs mapping table. */ +static const uint8_t s626_trimadrs[] = { + 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 +}; -/* Private helper function: Transmit serial data to DAC via Audio +/* + * Private helper function: Transmit serial data to DAC via Audio * channel 2. Assumes: (1) TSL2 slot records initialized, and (2) - * Dacpol contains valid target image. + * dacpol contains valid target image. */ -static void SendDAC(struct comedi_device *dev, uint32_t val) +static void s626_send_dac(struct comedi_device *dev, uint32_t val) { struct s626_private *devpriv = dev->private; /* START THE SERIAL CLOCK RUNNING ------------- */ - /* Assert DAC polarity control and enable gating of DAC serial clock + /* + * Assert DAC polarity control and enable gating of DAC serial clock * and audio bit stream signals. At this point in time we must be * assured of being in time slot 0. If we are not in slot 0, the * serial clock and audio stream signals will be disabled; this is - * because the following DEBIwrite statement (which enables signals - * to be passed through the gate array) would execute before the - * trailing edge of WS1/WS3 (which turns off the signals), thus + * because the following s626_debi_write statement (which enables + * signals to be passed through the gate array) would execute before + * the trailing edge of WS1/WS3 (which turns off the signals), thus * causing the signals to be inactive during the DAC write. */ - DEBIwrite(dev, LP_DACPOL, devpriv->Dacpol); + s626_debi_write(dev, S626_LP_DACPOL, devpriv->dacpol); /* TRANSFER OUTPUT DWORD VALUE INTO A2'S OUTPUT FIFO ---------------- */ /* Copy DAC setpoint value to DAC's output DMA buffer. */ - - /* writel(val, devpriv->mmio + (uint32_t)devpriv->pDacWBuf); */ - *devpriv->pDacWBuf = val; + /* writel(val, devpriv->mmio + (uint32_t)devpriv->dac_wbuf); */ + *devpriv->dac_wbuf = val; /* * Enable the output DMA transfer. This will cause the DMAC to copy @@ -362,56 +386,62 @@ static void SendDAC(struct comedi_device *dev, uint32_t val) * then immediately terminate because the protection address is * reached upon transfer of the first DWORD value. */ - s626_mc_enable(dev, MC1_A2OUT, P_MC1); + s626_mc_enable(dev, S626_MC1_A2OUT, S626_P_MC1); - /* While the DMA transfer is executing ... */ + /* While the DMA transfer is executing ... */ /* * Reset Audio2 output FIFO's underflow flag (along with any * other FIFO underflow/overflow flags). When set, this flag * will indicate that we have emerged from slot 0. */ - writel(ISR_AFOU, devpriv->mmio + P_ISR); + writel(S626_ISR_AFOU, devpriv->mmio + S626_P_ISR); - /* Wait for the DMA transfer to finish so that there will be data + /* + * Wait for the DMA transfer to finish so that there will be data * available in the FIFO when time slot 1 tries to transfer a DWORD * from the FIFO to the output buffer register. We test for DMA * Done by polling the DMAC enable flag; this flag is automatically * cleared when the transfer has finished. */ - while (readl(devpriv->mmio + P_MC1) & MC1_A2OUT) + while (readl(devpriv->mmio + S626_P_MC1) & S626_MC1_A2OUT) ; /* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */ - /* FIFO data is now available, so we enable execution of time slots + /* + * FIFO data is now available, so we enable execution of time slots * 1 and higher by clearing the EOS flag in slot 0. Note that SD3 * will be shifted in and stored in FB_BUFFER2 for end-of-slot-list * detection. */ - writel(XSD2 | RSD3 | SIB_A2, devpriv->mmio + VECTPORT(0)); + writel(S626_XSD2 | S626_RSD3 | S626_SIB_A2, + devpriv->mmio + S626_VECTPORT(0)); - /* Wait for slot 1 to execute to ensure that the Packet will be + /* + * Wait for slot 1 to execute to ensure that the Packet will be * transmitted. This is detected by polling the Audio2 output FIFO * underflow flag, which will be set when slot 1 execution has * finished transferring the DAC's data DWORD from the output FIFO * to the output buffer register. */ - while (!(readl(devpriv->mmio + P_SSR) & SSR_AF2_OUT)) + while (!(readl(devpriv->mmio + S626_P_SSR) & S626_SSR_AF2_OUT)) ; - /* Set up to trap execution at slot 0 when the TSL sequencer cycles + /* + * Set up to trap execution at slot 0 when the TSL sequencer cycles * back to slot 0 after executing the EOS in slot 5. Also, * simultaneously shift out and in the 0x00 that is ALWAYS the value * stored in the last byte to be shifted out of the FIFO's DWORD * buffer register. */ - writel(XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS, - devpriv->mmio + VECTPORT(0)); + writel(S626_XSD2 | S626_XFIFO_2 | S626_RSD2 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); /* WAIT FOR THE TRANSACTION TO FINISH ----------------------- */ - /* Wait for the TSL to finish executing all time slots before + /* + * Wait for the TSL to finish executing all time slots before * exiting this function. We must do this so that the next DAC * write doesn't start, thereby enabling clock/chip select signals: * @@ -428,17 +458,19 @@ static void SendDAC(struct comedi_device *dev, uint32_t val) * we test for the FB_BUFFER2 MSB contents to be equal to 0xFF. If * the TSL has not yet finished executing slot 5 ... */ - if (readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000) { - /* The trap was set on time and we are still executing somewhere + if (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000) { + /* + * The trap was set on time and we are still executing somewhere * in slots 2-5, so we now wait for slot 0 to execute and trap * TSL execution. This is detected when FB_BUFFER2 MSB changes * from 0xFF to 0x00, which slot 0 causes to happen by shifting * out/in on SD2 the 0x00 that is always referenced by slot 5. */ - while (readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000) + while (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000) ; } - /* Either (1) we were too late setting the slot 0 trap; the TSL + /* + * Either (1) we were too late setting the slot 0 trap; the TSL * sequencer restarted slot 0 before we could set the EOS trap flag, * or (2) we were not late and execution is now trapped at slot 0. * In either case, we must now change slot 0 so that it will store @@ -446,37 +478,46 @@ static void SendDAC(struct comedi_device *dev, uint32_t val) * In order to do this, we reprogram slot 0 so that it will shift in * SD3, which is driven only by a pull-up resistor. */ - writel(RSD3 | SIB_A2 | EOS, devpriv->mmio + VECTPORT(0)); + writel(S626_RSD3 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); - /* Wait for slot 0 to execute, at which time the TSL is setup for + /* + * Wait for slot 0 to execute, at which time the TSL is setup for * the next DAC write. This is detected when FB_BUFFER2 MSB changes * from 0x00 to 0xFF. */ - while (!(readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000)) + while (!(readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000)) ; } -/* Private helper function: Write setpoint to an application DAC channel. */ -static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata) +/* + * Private helper function: Write setpoint to an application DAC channel. + */ +static void s626_set_dac(struct comedi_device *dev, uint16_t chan, + unsigned short dacdata) { struct s626_private *devpriv = dev->private; - register uint16_t signmask; - register uint32_t WSImage; + uint16_t signmask; + uint32_t ws_image; + uint32_t val; - /* Adjust DAC data polarity and set up Polarity Control Register */ - /* image. */ + /* + * Adjust DAC data polarity and set up Polarity Control Register image. + */ signmask = 1 << chan; if (dacdata < 0) { dacdata = -dacdata; - devpriv->Dacpol |= signmask; - } else - devpriv->Dacpol &= ~signmask; + devpriv->dacpol |= signmask; + } else { + devpriv->dacpol &= ~signmask; + } - /* Limit DAC setpoint value to valid range. */ - if ((uint16_t) dacdata > 0x1FFF) + /* Limit DAC setpoint value to valid range. */ + if ((uint16_t)dacdata > 0x1FFF) dacdata = 0x1FFF; - /* Set up TSL2 records (aka "vectors") for DAC update. Vectors V2 + /* + * Set up TSL2 records (aka "vectors") for DAC update. Vectors V2 * and V3 transmit the setpoint to the target DAC. V4 and V5 send * data to a non-existent TrimDac channel just to keep the clock * running after sending data to the target DAC. This is necessary @@ -487,140 +528,811 @@ static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata) */ /* Choose DAC chip select to be asserted */ - WSImage = (chan & 2) ? WS1 : WS2; + ws_image = (chan & 2) ? S626_WS1 : S626_WS2; /* Slot 2: Transmit high data byte to target DAC */ - writel(XSD2 | XFIFO_1 | WSImage, devpriv->mmio + VECTPORT(2)); + writel(S626_XSD2 | S626_XFIFO_1 | ws_image, + devpriv->mmio + S626_VECTPORT(2)); /* Slot 3: Transmit low data byte to target DAC */ - writel(XSD2 | XFIFO_0 | WSImage, devpriv->mmio + VECTPORT(3)); + writel(S626_XSD2 | S626_XFIFO_0 | ws_image, + devpriv->mmio + S626_VECTPORT(3)); /* Slot 4: Transmit to non-existent TrimDac channel to keep clock */ - writel(XSD2 | XFIFO_3 | WS3, devpriv->mmio + VECTPORT(4)); + writel(S626_XSD2 | S626_XFIFO_3 | S626_WS3, + devpriv->mmio + S626_VECTPORT(4)); /* Slot 5: running after writing target DAC's low data byte */ - writel(XSD2 | XFIFO_2 | WS3 | EOS, devpriv->mmio + VECTPORT(5)); + writel(S626_XSD2 | S626_XFIFO_2 | S626_WS3 | S626_EOS, + devpriv->mmio + S626_VECTPORT(5)); - /* Construct and transmit target DAC's serial packet: - * ( A10D DDDD ),( DDDD DDDD ),( 0x0F ),( 0x00 ) where A is chan<0>, + /* + * Construct and transmit target DAC's serial packet: + * (A10D DDDD), (DDDD DDDD), (0x0F), (0x00) where A is chan<0>, * and D<12:0> is the DAC setpoint. Append a WORD value (that writes * to a non-existent TrimDac channel) that serves to keep the clock * running after the packet has been sent to the target DAC. */ - SendDAC(dev, 0x0F000000 - /* Continue clock after target DAC data (write to non-existent trimdac). */ - | 0x00004000 - /* Address the two main dual-DAC devices (TSL's chip select enables - * target device). */ - | ((uint32_t) (chan & 1) << 15) - /* Address the DAC channel within the device. */ - | (uint32_t) dacdata); /* Include DAC setpoint data. */ - + val = 0x0F000000; /* Continue clock after target DAC data + * (write to non-existent trimdac). */ + val |= 0x00004000; /* Address the two main dual-DAC devices + * (TSL's chip select enables target device). */ + val |= ((uint32_t)(chan & 1) << 15); /* Address the DAC channel + * within the device. */ + val |= (uint32_t)dacdata; /* Include DAC setpoint data. */ + s626_send_dac(dev, val); } -static void WriteTrimDAC(struct comedi_device *dev, uint8_t LogicalChan, - uint8_t DacData) +static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, + uint8_t dac_data) { struct s626_private *devpriv = dev->private; uint32_t chan; - /* Save the new setpoint in case the application needs to read it back later. */ - devpriv->TrimSetpoint[LogicalChan] = (uint8_t) DacData; + /* + * Save the new setpoint in case the application needs to read it back + * later. + */ + devpriv->trim_setpoint[logical_chan] = (uint8_t)dac_data; - /* Map logical channel number to physical channel number. */ - chan = (uint32_t) trimchan[LogicalChan]; + /* Map logical channel number to physical channel number. */ + chan = s626_trimchan[logical_chan]; - /* Set up TSL2 records for TrimDac write operation. All slots shift + /* + * Set up TSL2 records for TrimDac write operation. All slots shift * 0xFF in from pulled-up SD3 so that the end of the slot sequence * can be detected. */ /* Slot 2: Send high uint8_t to target TrimDac */ - writel(XSD2 | XFIFO_1 | WS3, devpriv->mmio + VECTPORT(2)); + writel(S626_XSD2 | S626_XFIFO_1 | S626_WS3, + devpriv->mmio + S626_VECTPORT(2)); /* Slot 3: Send low uint8_t to target TrimDac */ - writel(XSD2 | XFIFO_0 | WS3, devpriv->mmio + VECTPORT(3)); + writel(S626_XSD2 | S626_XFIFO_0 | S626_WS3, + devpriv->mmio + S626_VECTPORT(3)); /* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running */ - writel(XSD2 | XFIFO_3 | WS1, devpriv->mmio + VECTPORT(4)); + writel(S626_XSD2 | S626_XFIFO_3 | S626_WS1, + devpriv->mmio + S626_VECTPORT(4)); /* Slot 5: Send NOP low uint8_t to DAC0 */ - writel(XSD2 | XFIFO_2 | WS1 | EOS, devpriv->mmio + VECTPORT(5)); + writel(S626_XSD2 | S626_XFIFO_2 | S626_WS1 | S626_EOS, + devpriv->mmio + S626_VECTPORT(5)); - /* Construct and transmit target DAC's serial packet: - * ( 0000 AAAA ), ( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the + /* + * Construct and transmit target DAC's serial packet: + * (0000 AAAA), (DDDD DDDD), (0x00), (0x00) where A<3:0> is the * DAC channel's address, and D<7:0> is the DAC setpoint. Append a * WORD value (that writes a channel 0 NOP command to a non-existent * main DAC channel) that serves to keep the clock running after the * packet has been sent to the target DAC. */ - /* Address the DAC channel within the trimdac device. */ - SendDAC(dev, ((uint32_t) chan << 8) - | (uint32_t) DacData); /* Include DAC setpoint data. */ + /* + * Address the DAC channel within the trimdac device. + * Include DAC setpoint data. + */ + s626_send_dac(dev, (chan << 8) | dac_data); } -static void LoadTrimDACs(struct comedi_device *dev) +static void s626_load_trim_dacs(struct comedi_device *dev) { - register uint8_t i; + uint8_t i; - /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ - for (i = 0; i < ARRAY_SIZE(trimchan); i++) - WriteTrimDAC(dev, i, I2Cread(dev, trimadrs[i])); + /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ + for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) + s626_write_trim_dac(dev, i, + s626_i2c_read(dev, s626_trimadrs[i])); } /* ****** COUNTER FUNCTIONS ******* */ -/* All counter functions address a specific counter by means of the + +/* + * All counter functions address a specific counter by means of the * "Counter" argument, which is a logical counter number. The Counter * argument may have any of the following legal values: 0=0A, 1=1A, * 2=2A, 3=0B, 4=1B, 5=2B. */ -/* Read a counter's output latch. */ -static uint32_t ReadLatch(struct comedi_device *dev, struct enc_private *k) +/* + * Read a counter's output latch. + */ +static uint32_t s626_read_latch(struct comedi_device *dev, + const struct s626_enc_info *k) { - register uint32_t value; + uint32_t value; - /* Latch counts and fetch LSW of latched counts value. */ - value = (uint32_t) DEBIread(dev, k->MyLatchLsw); + /* Latch counts and fetch LSW of latched counts value. */ + value = s626_debi_read(dev, k->my_latch_lsw); - /* Fetch MSW of latched counts and combine with LSW. */ - value |= ((uint32_t) DEBIread(dev, k->MyLatchLsw + 2) << 16); + /* Fetch MSW of latched counts and combine with LSW. */ + value |= ((uint32_t)s626_debi_read(dev, k->my_latch_lsw + 2) << 16); - /* Return latched counts. */ + /* Return latched counts. */ return value; } -/* Return/set a counter pair's latch trigger source. 0: On read +/* + * Return/set a counter pair's latch trigger source. 0: On read * access, 1: A index latches A, 2: B index latches B, 3: A overflow * latches B. */ -static void SetLatchSource(struct comedi_device *dev, struct enc_private *k, - uint16_t value) +static void s626_set_latch_source(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) { - DEBIreplace(dev, k->MyCRB, - ~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC), - value << CRBBIT_LATCHSRC); + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_LATCHSRC), + value << S626_CRBBIT_LATCHSRC); } -/* Write value into counter preload register. */ -static void Preload(struct comedi_device *dev, struct enc_private *k, - uint32_t value) +/* + * Write value into counter preload register. + */ +static void s626_preload(struct comedi_device *dev, + const struct s626_enc_info *k, uint32_t value) { - DEBIwrite(dev, (uint16_t) (k->MyLatchLsw), (uint16_t) value); - DEBIwrite(dev, (uint16_t) (k->MyLatchLsw + 2), - (uint16_t) (value >> 16)); + s626_debi_write(dev, k->my_latch_lsw, value); + s626_debi_write(dev, k->my_latch_lsw + 2, value >> 16); } -static unsigned int s626_ai_reg_to_uint(int data) +/* ****** PRIVATE COUNTER FUNCTIONS ****** */ + +/* + * Reset a counter's index and overflow event capture flags. + */ +static void s626_reset_cap_flags_a(struct comedi_device *dev, + const struct s626_enc_info *k) { - unsigned int tempdata; + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + S626_CRBMSK_INTRESETCMD | S626_CRBMSK_INTRESET_A); +} - tempdata = (data >> 18); - if (tempdata & 0x2000) - tempdata &= 0x1fff; - else - tempdata += (1 << 13); +static void s626_reset_cap_flags_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + S626_CRBMSK_INTRESETCMD | S626_CRBMSK_INTRESET_B); +} + +/* + * Return counter setup in a format (COUNTER_SETUP) that is consistent + * for both A and B counters. + */ +static uint16_t s626_get_mode_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; + uint16_t crb; + uint16_t setup; + + /* Fetch CRA and CRB register images. */ + cra = s626_debi_read(dev, k->my_cra); + crb = s626_debi_read(dev, k->my_crb); + + /* + * Populate the standardized counter setup bit fields. + * Note: IndexSrc is restricted to ENC_X or IndxPol. + */ + setup = (cra & S626_STDMSK_LOADSRC) | /* LoadSrc = LoadSrcA. */ + ((crb << (S626_STDBIT_LATCHSRC - S626_CRBBIT_LATCHSRC)) & + S626_STDMSK_LATCHSRC) | /* LatchSrc = LatchSrcA. */ + ((cra << (S626_STDBIT_INTSRC - S626_CRABIT_INTSRC_A)) & + S626_STDMSK_INTSRC) | /* IntSrc = IntSrcA. */ + ((cra << (S626_STDBIT_INDXSRC - (S626_CRABIT_INDXSRC_A + 1))) & + S626_STDMSK_INDXSRC) | /* IndxSrc = IndxSrcA<1>. */ + ((cra >> (S626_CRABIT_INDXPOL_A - S626_STDBIT_INDXPOL)) & + S626_STDMSK_INDXPOL) | /* IndxPol = IndxPolA. */ + ((crb >> (S626_CRBBIT_CLKENAB_A - S626_STDBIT_CLKENAB)) & + S626_STDMSK_CLKENAB); /* ClkEnab = ClkEnabA. */ + + /* Adjust mode-dependent parameters. */ + if (cra & (2 << S626_CRABIT_CLKSRC_A)) { + /* Timer mode (ClkSrcA<1> == 1): */ + /* Indicate Timer mode. */ + setup |= S626_CLKSRC_TIMER << S626_STDBIT_CLKSRC; + /* Set ClkPol to indicate count direction (ClkSrcA<0>). */ + setup |= (cra << (S626_STDBIT_CLKPOL - S626_CRABIT_CLKSRC_A)) & + S626_STDMSK_CLKPOL; + /* ClkMult must be 1x in Timer mode. */ + setup |= S626_MULT_X1 << S626_STDBIT_CLKMULT; + } else { + /* Counter mode (ClkSrcA<1> == 0): */ + /* Indicate Counter mode. */ + setup |= S626_CLKSRC_COUNTER << S626_STDBIT_CLKSRC; + /* Pass through ClkPol. */ + setup |= (cra >> (S626_CRABIT_CLKPOL_A - S626_STDBIT_CLKPOL)) & + S626_STDMSK_CLKPOL; + /* Force ClkMult to 1x if not legal, else pass through. */ + if ((cra & S626_CRAMSK_CLKMULT_A) == + (S626_MULT_X0 << S626_CRABIT_CLKMULT_A)) + setup |= S626_MULT_X1 << S626_STDBIT_CLKMULT; + else + setup |= (cra >> (S626_CRABIT_CLKMULT_A - + S626_STDBIT_CLKMULT)) & + S626_STDMSK_CLKMULT; + } + + /* Return adjusted counter setup. */ + return setup; +} + +static uint16_t s626_get_mode_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; + uint16_t crb; + uint16_t setup; + + /* Fetch CRA and CRB register images. */ + cra = s626_debi_read(dev, k->my_cra); + crb = s626_debi_read(dev, k->my_crb); + + /* + * Populate the standardized counter setup bit fields. + * Note: IndexSrc is restricted to ENC_X or IndxPol. + */ + setup = ((crb << (S626_STDBIT_INTSRC - S626_CRBBIT_INTSRC_B)) & + S626_STDMSK_INTSRC) | /* IntSrc = IntSrcB. */ + ((crb << (S626_STDBIT_LATCHSRC - S626_CRBBIT_LATCHSRC)) & + S626_STDMSK_LATCHSRC) | /* LatchSrc = LatchSrcB. */ + ((crb << (S626_STDBIT_LOADSRC - S626_CRBBIT_LOADSRC_B)) & + S626_STDMSK_LOADSRC) | /* LoadSrc = LoadSrcB. */ + ((crb << (S626_STDBIT_INDXPOL - S626_CRBBIT_INDXPOL_B)) & + S626_STDMSK_INDXPOL) | /* IndxPol = IndxPolB. */ + ((crb >> (S626_CRBBIT_CLKENAB_B - S626_STDBIT_CLKENAB)) & + S626_STDMSK_CLKENAB) | /* ClkEnab = ClkEnabB. */ + ((cra >> ((S626_CRABIT_INDXSRC_B + 1) - S626_STDBIT_INDXSRC)) & + S626_STDMSK_INDXSRC); /* IndxSrc = IndxSrcB<1>. */ + + /* Adjust mode-dependent parameters. */ + if ((crb & S626_CRBMSK_CLKMULT_B) == + (S626_MULT_X0 << S626_CRBBIT_CLKMULT_B)) { + /* Extender mode (ClkMultB == S626_MULT_X0): */ + /* Indicate Extender mode. */ + setup |= S626_CLKSRC_EXTENDER << S626_STDBIT_CLKSRC; + /* Indicate multiplier is 1x. */ + setup |= S626_MULT_X1 << S626_STDBIT_CLKMULT; + /* Set ClkPol equal to Timer count direction (ClkSrcB<0>). */ + setup |= (cra >> (S626_CRABIT_CLKSRC_B - S626_STDBIT_CLKPOL)) & + S626_STDMSK_CLKPOL; + } else if (cra & (2 << S626_CRABIT_CLKSRC_B)) { + /* Timer mode (ClkSrcB<1> == 1): */ + /* Indicate Timer mode. */ + setup |= S626_CLKSRC_TIMER << S626_STDBIT_CLKSRC; + /* Indicate multiplier is 1x. */ + setup |= S626_MULT_X1 << S626_STDBIT_CLKMULT; + /* Set ClkPol equal to Timer count direction (ClkSrcB<0>). */ + setup |= (cra >> (S626_CRABIT_CLKSRC_B - S626_STDBIT_CLKPOL)) & + S626_STDMSK_CLKPOL; + } else { + /* If Counter mode (ClkSrcB<1> == 0): */ + /* Indicate Timer mode. */ + setup |= S626_CLKSRC_COUNTER << S626_STDBIT_CLKSRC; + /* Clock multiplier is passed through. */ + setup |= (crb >> (S626_CRBBIT_CLKMULT_B - + S626_STDBIT_CLKMULT)) & S626_STDMSK_CLKMULT; + /* Clock polarity is passed through. */ + setup |= (crb << (S626_STDBIT_CLKPOL - S626_CRBBIT_CLKPOL_B)) & + S626_STDMSK_CLKPOL; + } + + /* Return adjusted counter setup. */ + return setup; +} + +/* + * Set the operating mode for the specified counter. The setup + * parameter is treated as a COUNTER_SETUP data type. The following + * parameters are programmable (all other parms are ignored): ClkMult, + * ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc. + */ +static void s626_set_mode_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src) +{ + struct s626_private *devpriv = dev->private; + uint16_t cra; + uint16_t crb; + + /* Initialize CRA and CRB images. */ + /* Preload trigger is passed through. */ + cra = setup & S626_CRAMSK_LOADSRC_A; + /* IndexSrc is restricted to ENC_X or IndxPol. */ + cra |= (setup & S626_STDMSK_INDXSRC) >> + (S626_STDBIT_INDXSRC - (S626_CRABIT_INDXSRC_A + 1)); + + /* Reset any pending CounterA event captures. */ + crb = S626_CRBMSK_INTRESETCMD | S626_CRBMSK_INTRESET_A; + /* Clock enable is passed through. */ + crb |= (setup & S626_STDMSK_CLKENAB) << + (S626_CRBBIT_CLKENAB_A - S626_STDBIT_CLKENAB); + + /* Force IntSrc to Disabled if disable_int_src is asserted. */ + if (!disable_int_src) + cra |= (setup & S626_STDMSK_INTSRC) >> + (S626_STDBIT_INTSRC - S626_CRABIT_INTSRC_A); + + /* Populate all mode-dependent attributes of CRA & CRB images. */ + switch ((setup & S626_STDMSK_CLKSRC) >> S626_STDBIT_CLKSRC) { + case S626_CLKSRC_EXTENDER: /* Extender Mode: */ + /* Force to Timer mode (Extender valid only for B counters). */ + /* Fall through to case S626_CLKSRC_TIMER: */ + case S626_CLKSRC_TIMER: /* Timer Mode: */ + /* ClkSrcA<1> selects system clock */ + cra |= 2 << S626_CRABIT_CLKSRC_A; + /* Count direction (ClkSrcA<0>) obtained from ClkPol. */ + cra |= (setup & S626_STDMSK_CLKPOL) >> + (S626_STDBIT_CLKPOL - S626_CRABIT_CLKSRC_A); + /* ClkPolA behaves as always-on clock enable. */ + cra |= 1 << S626_CRABIT_CLKPOL_A; + /* ClkMult must be 1x. */ + cra |= S626_MULT_X1 << S626_CRABIT_CLKMULT_A; + break; + default: /* Counter Mode: */ + /* Select ENC_C and ENC_D as clock/direction inputs. */ + cra |= S626_CLKSRC_COUNTER; + /* Clock polarity is passed through. */ + cra |= (setup & S626_STDMSK_CLKPOL) << + (S626_CRABIT_CLKPOL_A - S626_STDBIT_CLKPOL); + /* Force multiplier to x1 if not legal, else pass through. */ + if ((setup & S626_STDMSK_CLKMULT) == + (S626_MULT_X0 << S626_STDBIT_CLKMULT)) + cra |= S626_MULT_X1 << S626_CRABIT_CLKMULT_A; + else + cra |= (setup & S626_STDMSK_CLKMULT) << + (S626_CRABIT_CLKMULT_A - S626_STDBIT_CLKMULT); + break; + } + + /* + * Force positive index polarity if IndxSrc is software-driven only, + * otherwise pass it through. + */ + if (~setup & S626_STDMSK_INDXSRC) + cra |= (setup & S626_STDMSK_INDXPOL) << + (S626_CRABIT_INDXPOL_A - S626_STDBIT_INDXPOL); + + /* + * If IntSrc has been forced to Disabled, update the MISC2 interrupt + * enable mask to indicate the counter interrupt is disabled. + */ + if (disable_int_src) + devpriv->counter_int_enabs &= ~k->my_event_bits[3]; + + /* + * While retaining CounterB and LatchSrc configurations, program the + * new counter operating mode. + */ + s626_debi_replace(dev, k->my_cra, + S626_CRAMSK_INDXSRC_B | S626_CRAMSK_CLKSRC_B, cra); + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_A), crb); +} + +static void s626_set_mode_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src) +{ + struct s626_private *devpriv = dev->private; + uint16_t cra; + uint16_t crb; + + /* Initialize CRA and CRB images. */ + /* IndexSrc field is restricted to ENC_X or IndxPol. */ + cra = (setup & S626_STDMSK_INDXSRC) << + (S626_CRABIT_INDXSRC_B + 1 - S626_STDBIT_INDXSRC); + + /* Reset event captures and disable interrupts. */ + crb = S626_CRBMSK_INTRESETCMD | S626_CRBMSK_INTRESET_B; + /* Clock enable is passed through. */ + crb |= (setup & S626_STDMSK_CLKENAB) << + (S626_CRBBIT_CLKENAB_B - S626_STDBIT_CLKENAB); + /* Preload trigger source is passed through. */ + crb |= (setup & S626_STDMSK_LOADSRC) >> + (S626_STDBIT_LOADSRC - S626_CRBBIT_LOADSRC_B); + + /* Force IntSrc to Disabled if disable_int_src is asserted. */ + if (!disable_int_src) + crb |= (setup & S626_STDMSK_INTSRC) >> + (S626_STDBIT_INTSRC - S626_CRBBIT_INTSRC_B); + + /* Populate all mode-dependent attributes of CRA & CRB images. */ + switch ((setup & S626_STDMSK_CLKSRC) >> S626_STDBIT_CLKSRC) { + case S626_CLKSRC_TIMER: /* Timer Mode: */ + /* ClkSrcB<1> selects system clock */ + cra |= 2 << S626_CRABIT_CLKSRC_B; + /* with direction (ClkSrcB<0>) obtained from ClkPol. */ + cra |= (setup & S626_STDMSK_CLKPOL) << + (S626_CRABIT_CLKSRC_B - S626_STDBIT_CLKPOL); + /* ClkPolB behaves as always-on clock enable. */ + crb |= 1 << S626_CRBBIT_CLKPOL_B; + /* ClkMultB must be 1x. */ + crb |= S626_MULT_X1 << S626_CRBBIT_CLKMULT_B; + break; + case S626_CLKSRC_EXTENDER: /* Extender Mode: */ + /* ClkSrcB source is OverflowA (same as "timer") */ + cra |= 2 << S626_CRABIT_CLKSRC_B; + /* with direction obtained from ClkPol. */ + cra |= (setup & S626_STDMSK_CLKPOL) << + (S626_CRABIT_CLKSRC_B - S626_STDBIT_CLKPOL); + /* ClkPolB controls IndexB -- always set to active. */ + crb |= 1 << S626_CRBBIT_CLKPOL_B; + /* ClkMultB selects OverflowA as the clock source. */ + crb |= S626_MULT_X0 << S626_CRBBIT_CLKMULT_B; + break; + default: /* Counter Mode: */ + /* Select ENC_C and ENC_D as clock/direction inputs. */ + cra |= S626_CLKSRC_COUNTER << S626_CRABIT_CLKSRC_B; + /* ClkPol is passed through. */ + crb |= (setup & S626_STDMSK_CLKPOL) >> + (S626_STDBIT_CLKPOL - S626_CRBBIT_CLKPOL_B); + /* Force ClkMult to x1 if not legal, otherwise pass through. */ + if ((setup & S626_STDMSK_CLKMULT) == + (S626_MULT_X0 << S626_STDBIT_CLKMULT)) + crb |= S626_MULT_X1 << S626_CRBBIT_CLKMULT_B; + else + crb |= (setup & S626_STDMSK_CLKMULT) << + (S626_CRBBIT_CLKMULT_B - S626_STDBIT_CLKMULT); + break; + } + + /* + * Force positive index polarity if IndxSrc is software-driven only, + * otherwise pass it through. + */ + if (~setup & S626_STDMSK_INDXSRC) + crb |= (setup & S626_STDMSK_INDXPOL) >> + (S626_STDBIT_INDXPOL - S626_CRBBIT_INDXPOL_B); + + /* + * If IntSrc has been forced to Disabled, update the MISC2 interrupt + * enable mask to indicate the counter interrupt is disabled. + */ + if (disable_int_src) + devpriv->counter_int_enabs &= ~k->my_event_bits[3]; + + /* + * While retaining CounterA and LatchSrc configurations, program the + * new counter operating mode. + */ + s626_debi_replace(dev, k->my_cra, + ~(S626_CRAMSK_INDXSRC_B | S626_CRAMSK_CLKSRC_B), cra); + s626_debi_replace(dev, k->my_crb, + S626_CRBMSK_CLKENAB_A | S626_CRBMSK_LATCHSRC, crb); +} + +/* + * Return/set a counter's enable. enab: 0=always enabled, 1=enabled by index. + */ +static void s626_set_enable_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_A), + enab << S626_CRBBIT_CLKENAB_A); +} + +static void s626_set_enable_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_B), + enab << S626_CRBBIT_CLKENAB_B); +} + +static uint16_t s626_get_enable_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (s626_debi_read(dev, k->my_crb) >> S626_CRBBIT_CLKENAB_A) & 1; +} + +static uint16_t s626_get_enable_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (s626_debi_read(dev, k->my_crb) >> S626_CRBBIT_CLKENAB_B) & 1; +} + +#ifdef unused +static uint16_t s626_get_latch_source(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (s626_debi_read(dev, k->my_crb) >> S626_CRBBIT_LATCHSRC) & 3; +} +#endif + +/* + * Return/set the event that will trigger transfer of the preload + * register into the counter. 0=ThisCntr_Index, 1=ThisCntr_Overflow, + * 2=OverflowA (B counters only), 3=disabled. + */ +static void s626_set_load_trig_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig) +{ + s626_debi_replace(dev, k->my_cra, ~S626_CRAMSK_LOADSRC_A, + trig << S626_CRABIT_LOADSRC_A); +} + +static void s626_set_load_trig_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_LOADSRC_B | S626_CRBMSK_INTCTRL), + trig << S626_CRBBIT_LOADSRC_B); +} + +static uint16_t s626_get_load_trig_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (s626_debi_read(dev, k->my_cra) >> S626_CRABIT_LOADSRC_A) & 3; +} + +static uint16_t s626_get_load_trig_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (s626_debi_read(dev, k->my_crb) >> S626_CRBBIT_LOADSRC_B) & 3; +} + +/* + * Return/set counter interrupt source and clear any captured + * index/overflow events. int_source: 0=Disabled, 1=OverflowOnly, + * 2=IndexOnly, 3=IndexAndOverflow. + */ +static void s626_set_int_src_a(struct comedi_device *dev, + const struct s626_enc_info *k, + uint16_t int_source) +{ + struct s626_private *devpriv = dev->private; + + /* Reset any pending counter overflow or index captures. */ + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + S626_CRBMSK_INTRESETCMD | S626_CRBMSK_INTRESET_A); + + /* Program counter interrupt source. */ + s626_debi_replace(dev, k->my_cra, ~S626_CRAMSK_INTSRC_A, + int_source << S626_CRABIT_INTSRC_A); + + /* Update MISC2 interrupt enable mask. */ + devpriv->counter_int_enabs = + (devpriv->counter_int_enabs & ~k->my_event_bits[3]) | + k->my_event_bits[int_source]; +} + +static void s626_set_int_src_b(struct comedi_device *dev, + const struct s626_enc_info *k, + uint16_t int_source) +{ + struct s626_private *devpriv = dev->private; + uint16_t crb; + + /* Cache writeable CRB register image. */ + crb = s626_debi_read(dev, k->my_crb) & ~S626_CRBMSK_INTCTRL; + + /* Reset any pending counter overflow or index captures. */ + s626_debi_write(dev, k->my_crb, (crb | S626_CRBMSK_INTRESETCMD | + S626_CRBMSK_INTRESET_B)); + + /* Program counter interrupt source. */ + s626_debi_write(dev, k->my_crb, + ((crb & ~S626_CRBMSK_INTSRC_B) | + (int_source << S626_CRBBIT_INTSRC_B))); + + /* Update MISC2 interrupt enable mask. */ + devpriv->counter_int_enabs = + (devpriv->counter_int_enabs & ~k->my_event_bits[3]) | + k->my_event_bits[int_source]; +} + +static uint16_t s626_get_int_src_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (s626_debi_read(dev, k->my_cra) >> S626_CRABIT_INTSRC_A) & 3; +} + +static uint16_t s626_get_int_src_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (s626_debi_read(dev, k->my_crb) >> S626_CRBBIT_INTSRC_B) & 3; +} + +#ifdef unused +/* + * Return/set the clock multiplier. + */ +static void s626_set_clk_mult(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_CLKMULT) | + (value << S626_STDBIT_CLKMULT)), false); +} + +static uint16_t s626_get_clk_mult(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (k->get_mode(dev, k) >> S626_STDBIT_CLKMULT) & 3; +} + +/* + * Return/set the clock polarity. + */ +static void s626_set_clk_pol(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_CLKPOL) | + (value << S626_STDBIT_CLKPOL)), false); +} + +static uint16_t s626_get_clk_pol(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (k->get_mode(dev, k) >> S626_STDBIT_CLKPOL) & 1; +} + +/* + * Return/set the clock source. + */ +static void s626_set_clk_src(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_CLKSRC) | + (value << S626_STDBIT_CLKSRC)), false); +} + +static uint16_t s626_get_clk_src(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (k->get_mode(dev, k) >> S626_STDBIT_CLKSRC) & 3; +} + +/* + * Return/set the index polarity. + */ +static void s626_set_index_pol(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_INDXPOL) | + ((value != 0) << S626_STDBIT_INDXPOL)), false); +} + +static uint16_t s626_get_index_pol(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (k->get_mode(dev, k) >> S626_STDBIT_INDXPOL) & 1; +} + +/* + * Return/set the index source. + */ +static void s626_set_index_src(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_INDXSRC) | + ((value != 0) << S626_STDBIT_INDXSRC)), false); +} + +static uint16_t s626_get_index_src(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return (k->get_mode(dev, k) >> S626_STDBIT_INDXSRC) & 1; +} +#endif - return tempdata; +/* + * Generate an index pulse. + */ +static void s626_pulse_index_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; + + cra = s626_debi_read(dev, k->my_cra); + /* Pulse index. */ + s626_debi_write(dev, k->my_cra, (cra ^ S626_CRAMSK_INDXPOL_A)); + s626_debi_write(dev, k->my_cra, cra); } -/* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data){ */ -/* return 0; */ -/* } */ +static void s626_pulse_index_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t crb; + + crb = s626_debi_read(dev, k->my_crb) & ~S626_CRBMSK_INTCTRL; + /* Pulse index. */ + s626_debi_write(dev, k->my_crb, (crb ^ S626_CRBMSK_INDXPOL_B)); + s626_debi_write(dev, k->my_crb, crb); +} + +static const struct s626_enc_info s626_enc_chan_info[] = { + { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR0A, + .my_crb = S626_LP_CR0B, + .my_latch_lsw = S626_LP_CNTR0ALSW, + .my_event_bits = S626_EVBITS(0), + }, { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR1A, + .my_crb = S626_LP_CR1B, + .my_latch_lsw = S626_LP_CNTR1ALSW, + .my_event_bits = S626_EVBITS(1), + }, { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR2A, + .my_crb = S626_LP_CR2B, + .my_latch_lsw = S626_LP_CNTR2ALSW, + .my_event_bits = S626_EVBITS(2), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR0A, + .my_crb = S626_LP_CR0B, + .my_latch_lsw = S626_LP_CNTR0BLSW, + .my_event_bits = S626_EVBITS(3), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR1A, + .my_crb = S626_LP_CR1B, + .my_latch_lsw = S626_LP_CNTR1BLSW, + .my_event_bits = S626_EVBITS(4), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR2A, + .my_crb = S626_LP_CR2B, + .my_latch_lsw = S626_LP_CNTR2BLSW, + .my_event_bits = S626_EVBITS(5), + }, +}; + +static unsigned int s626_ai_reg_to_uint(unsigned int data) +{ + return ((data >> 18) & 0x3fff) ^ 0x2000; +} static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan) { @@ -629,19 +1341,19 @@ static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan) unsigned int status; /* set channel to capture positive edge */ - status = DEBIread(dev, LP_RDEDGSEL(group)); - DEBIwrite(dev, LP_WREDGSEL(group), mask | status); + status = s626_debi_read(dev, S626_LP_RDEDGSEL(group)); + s626_debi_write(dev, S626_LP_WREDGSEL(group), mask | status); /* enable interrupt on selected channel */ - status = DEBIread(dev, LP_RDINTSEL(group)); - DEBIwrite(dev, LP_WRINTSEL(group), mask | status); + status = s626_debi_read(dev, S626_LP_RDINTSEL(group)); + s626_debi_write(dev, S626_LP_WRINTSEL(group), mask | status); /* enable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_EDCAP); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_EDCAP); /* enable edge capture on selected channel */ - status = DEBIread(dev, LP_RDCAPSEL(group)); - DEBIwrite(dev, LP_WRCAPSEL(group), mask | status); + status = s626_debi_read(dev, S626_LP_RDCAPSEL(group)); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), mask | status); return 0; } @@ -650,10 +1362,10 @@ static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int group, unsigned int mask) { /* disable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); /* enable edge capture on selected channel */ - DEBIwrite(dev, LP_WRCAPSEL(group), mask); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), mask); return 0; } @@ -663,17 +1375,17 @@ static int s626_dio_clear_irq(struct comedi_device *dev) unsigned int group; /* disable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); /* clear all dio pending events and interrupt */ for (group = 0; group < S626_DIO_BANKS; group++) - DEBIwrite(dev, LP_WRCAPSEL(group), 0xffff); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), 0xffff); return 0; } -static void handle_dio_interrupt(struct comedi_device *dev, - uint16_t irqbit, uint8_t group) +static void s626_handle_dio_interrupt(struct comedi_device *dev, + uint16_t irqbit, uint8_t group) { struct s626_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -686,7 +1398,7 @@ static void handle_dio_interrupt(struct comedi_device *dev, if ((irqbit >> (cmd->start_arg - (16 * group))) == 1 && cmd->start_src == TRIG_EXT) { /* Start executing the RPS program */ - s626_mc_enable(dev, MC1_ERPS1, P_MC1); + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); if (cmd->scan_begin_src == TRIG_EXT) s626_dio_set_irq(dev, cmd->scan_begin_arg); @@ -694,7 +1406,7 @@ static void handle_dio_interrupt(struct comedi_device *dev, if ((irqbit >> (cmd->scan_begin_arg - (16 * group))) == 1 && cmd->scan_begin_src == TRIG_EXT) { /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); if (cmd->convert_src == TRIG_EXT) { devpriv->ai_convert_count = cmd->chanlist_len; @@ -703,16 +1415,17 @@ static void handle_dio_interrupt(struct comedi_device *dev, } if (cmd->convert_src == TRIG_TIMER) { - struct enc_private *k = &encpriv[5]; + const struct s626_enc_info *k = + &s626_enc_chan_info[5]; devpriv->ai_convert_count = cmd->chanlist_len; - k->SetEnable(dev, k, CLKENAB_ALWAYS); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); } } if ((irqbit >> (cmd->convert_arg - (16 * group))) == 1 && cmd->convert_src == TRIG_EXT) { /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); devpriv->ai_convert_count--; if (devpriv->ai_convert_count > 0) @@ -721,7 +1434,7 @@ static void handle_dio_interrupt(struct comedi_device *dev, } } -static void check_dio_interrupts(struct comedi_device *dev) +static void s626_check_dio_interrupts(struct comedi_device *dev) { uint16_t irqbit; uint8_t group; @@ -729,90 +1442,91 @@ static void check_dio_interrupts(struct comedi_device *dev) for (group = 0; group < S626_DIO_BANKS; group++) { irqbit = 0; /* read interrupt type */ - irqbit = DEBIread(dev, LP_RDCAPFLG(group)); + irqbit = s626_debi_read(dev, S626_LP_RDCAPFLG(group)); /* check if interrupt is generated from dio channels */ if (irqbit) { - handle_dio_interrupt(dev, irqbit, group); + s626_handle_dio_interrupt(dev, irqbit, group); return; } } } -static void check_counter_interrupts(struct comedi_device *dev) +static void s626_check_counter_interrupts(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - struct enc_private *k; + const struct s626_enc_info *k; uint16_t irqbit; /* read interrupt type */ - irqbit = DEBIread(dev, LP_RDMISC2); + irqbit = s626_debi_read(dev, S626_LP_RDMISC2); /* check interrupt on counters */ - if (irqbit & IRQ_COINT1A) { - k = &encpriv[0]; + if (irqbit & S626_IRQ_COINT1A) { + k = &s626_enc_chan_info[0]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); } - if (irqbit & IRQ_COINT2A) { - k = &encpriv[1]; + if (irqbit & S626_IRQ_COINT2A) { + k = &s626_enc_chan_info[1]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); } - if (irqbit & IRQ_COINT3A) { - k = &encpriv[2]; + if (irqbit & S626_IRQ_COINT3A) { + k = &s626_enc_chan_info[2]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); } - if (irqbit & IRQ_COINT1B) { - k = &encpriv[3]; + if (irqbit & S626_IRQ_COINT1B) { + k = &s626_enc_chan_info[3]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); } - if (irqbit & IRQ_COINT2B) { - k = &encpriv[4]; + if (irqbit & S626_IRQ_COINT2B) { + k = &s626_enc_chan_info[4]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); if (devpriv->ai_convert_count > 0) { devpriv->ai_convert_count--; if (devpriv->ai_convert_count == 0) - k->SetEnable(dev, k, CLKENAB_INDEX); + k->set_enable(dev, k, S626_CLKENAB_INDEX); if (cmd->convert_src == TRIG_TIMER) { /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, + S626_P_MC2); } } } - if (irqbit & IRQ_COINT3B) { - k = &encpriv[5]; + if (irqbit & S626_IRQ_COINT3B) { + k = &s626_enc_chan_info[5]; /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + k->reset_cap_flags(dev, k); if (cmd->scan_begin_src == TRIG_TIMER) { /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); } if (cmd->convert_src == TRIG_TIMER) { - k = &encpriv[4]; + k = &s626_enc_chan_info[4]; devpriv->ai_convert_count = cmd->chanlist_len; - k->SetEnable(dev, k, CLKENAB_ALWAYS); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); } } } -static bool handle_eos_interrupt(struct comedi_device *dev) +static bool s626_handle_eos_interrupt(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -823,19 +1537,19 @@ static bool handle_eos_interrupt(struct comedi_device *dev) * first uint16_t in the buffer because it contains junk data * from the final ADC of the previous poll list scan. */ - int32_t *readaddr = (int32_t *)devpriv->ANABuf.LogicalBase + 1; + uint32_t *readaddr = (uint32_t *)devpriv->ana_buf.logical_base + 1; bool finished = false; int i; /* get the data and hand it over to comedi */ for (i = 0; i < cmd->chanlist_len; i++) { - short tempdata; + unsigned short tempdata; /* * Convert ADC data to 16-bit integer values and copy * to application buffer. */ - tempdata = s626_ai_reg_to_uint((int)*readaddr); + tempdata = s626_ai_reg_to_uint(*readaddr); readaddr++; /* put data into read buffer */ @@ -846,13 +1560,13 @@ static bool handle_eos_interrupt(struct comedi_device *dev) /* end of scan occurs */ async->events |= COMEDI_CB_EOS; - if (!devpriv->ai_continous) + if (!devpriv->ai_continuous) devpriv->ai_sample_count--; if (devpriv->ai_sample_count <= 0) { devpriv->ai_cmd_running = 0; /* Stop RPS program */ - s626_mc_disable(dev, MC1_ERPS1, P_MC1); + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); /* send end of acquisition */ async->events |= COMEDI_CB_EOA; @@ -879,229 +1593,238 @@ static irqreturn_t s626_irq_handler(int irq, void *d) if (!dev->attached) return IRQ_NONE; - /* lock to avoid race with comedi_poll */ + /* lock to avoid race with comedi_poll */ spin_lock_irqsave(&dev->spinlock, flags); /* save interrupt enable register state */ - irqstatus = readl(devpriv->mmio + P_IER); + irqstatus = readl(devpriv->mmio + S626_P_IER); /* read interrupt type */ - irqtype = readl(devpriv->mmio + P_ISR); + irqtype = readl(devpriv->mmio + S626_P_ISR); /* disable master interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* clear interrupt */ - writel(irqtype, devpriv->mmio + P_ISR); + writel(irqtype, devpriv->mmio + S626_P_ISR); switch (irqtype) { - case IRQ_RPS1: /* end_of_scan occurs */ - if (handle_eos_interrupt(dev)) + case S626_IRQ_RPS1: /* end_of_scan occurs */ + if (s626_handle_eos_interrupt(dev)) irqstatus = 0; break; - case IRQ_GPIO3: /* check dio and conter interrupt */ + case S626_IRQ_GPIO3: /* check dio and counter interrupt */ /* s626_dio_clear_irq(dev); */ - check_dio_interrupts(dev); - check_counter_interrupts(dev); + s626_check_dio_interrupts(dev); + s626_check_counter_interrupts(dev); break; } /* enable interrupt */ - writel(irqstatus, devpriv->mmio + P_IER); + writel(irqstatus, devpriv->mmio + S626_P_IER); spin_unlock_irqrestore(&dev->spinlock, flags); return IRQ_HANDLED; } /* - * this functions build the RPS program for hardware driven acquistion + * This function builds the RPS program for hardware driven acquisition. */ -static void ResetADC(struct comedi_device *dev, uint8_t *ppl) +static void s626_reset_adc(struct comedi_device *dev, uint8_t *ppl) { struct s626_private *devpriv = dev->private; - register uint32_t *pRPS; - uint32_t JmpAdrs; + uint32_t *rps; + uint32_t jmp_adrs; uint16_t i; uint16_t n; - uint32_t LocalPPL; - struct comedi_cmd *cmd = &(dev->subdevices->async->cmd); + uint32_t local_ppl; + struct comedi_cmd *cmd = &dev->subdevices->async->cmd; /* Stop RPS program in case it is currently running */ - s626_mc_disable(dev, MC1_ERPS1, P_MC1); + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); - /* Set starting logical address to write RPS commands. */ - pRPS = (uint32_t *) devpriv->RPSBuf.LogicalBase; + /* Set starting logical address to write RPS commands. */ + rps = (uint32_t *)devpriv->rps_buf.logical_base; /* Initialize RPS instruction pointer */ - writel((uint32_t)devpriv->RPSBuf.PhysicalBase, - devpriv->mmio + P_RPSADDR1); - - /* Construct RPS program in RPSBuf DMA buffer */ + writel((uint32_t)devpriv->rps_buf.physical_base, + devpriv->mmio + S626_P_RPSADDR1); + /* Construct RPS program in rps_buf DMA buffer */ if (cmd != NULL && cmd->scan_begin_src != TRIG_FOLLOW) { - /* Wait for Start trigger. */ - *pRPS++ = RPS_PAUSE | RPS_SIGADC; - *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC; + /* Wait for Start trigger. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_SIGADC; + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; } - /* SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary + /* + * SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary * because the first RPS DEBI Write following a non-RPS DEBI write * seems to always fail. If we don't do this dummy write, the ADC * gain might not be set to the value required for the first slot in * the poll list; the ADC gain would instead remain unchanged from * the previously programmed value. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); /* Write DEBI Write command and address to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_GSEL; + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + /* Write DEBI immediate data to shadow RAM: */ + *rps++ = S626_GSEL_BIPOLAR5V; /* arbitrary immediate data value. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Reset "shadow RAM uploaded" flag. */ + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; - *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); - /* Write DEBI immediate data to shadow RAM: */ - - *pRPS++ = GSEL_BIPOLAR5V; - /* arbitrary immediate data value. */ - - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; - /* Reset "shadow RAM uploaded" flag. */ - *pRPS++ = RPS_UPLOAD | RPS_DEBI; /* Invoke shadow RAM upload. */ - *pRPS++ = RPS_PAUSE | RPS_DEBI; /* Wait for shadow upload to finish. */ - - /* Digitize all slots in the poll list. This is implemented as a + /* + * Digitize all slots in the poll list. This is implemented as a * for loop to limit the slot count to 16 in case the application - * forgot to set the EOPL flag in the final slot. + * forgot to set the S626_EOPL flag in the final slot. */ - for (devpriv->AdcItems = 0; devpriv->AdcItems < 16; devpriv->AdcItems++) { - /* Convert application's poll list item to private board class + for (devpriv->adc_items = 0; devpriv->adc_items < 16; + devpriv->adc_items++) { + /* + * Convert application's poll list item to private board class * format. Each app poll list item is an uint8_t with form * (EOPL,x,x,RANGE,CHAN<3:0>), where RANGE code indicates 0 = * +-10V, 1 = +-5V, and EOPL = End of Poll List marker. */ - LocalPPL = - (*ppl << 8) | (*ppl & 0x10 ? GSEL_BIPOLAR5V : - GSEL_BIPOLAR10V); - - /* Switch ADC analog gain. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); /* Write DEBI command */ - /* and address to */ - /* shadow RAM. */ - *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); /* Write DEBI */ - /* immediate data to */ - /* shadow RAM. */ - *pRPS++ = LocalPPL; - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; /* Reset "shadow RAM uploaded" */ - /* flag. */ - *pRPS++ = RPS_UPLOAD | RPS_DEBI; /* Invoke shadow RAM upload. */ - *pRPS++ = RPS_PAUSE | RPS_DEBI; /* Wait for shadow upload to */ - /* finish. */ - - /* Select ADC analog input channel. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); - /* Write DEBI command and address to shadow RAM. */ - *pRPS++ = DEBI_CMD_WRWORD | LP_ISEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); - /* Write DEBI immediate data to shadow RAM. */ - *pRPS++ = LocalPPL; - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; - /* Reset "shadow RAM uploaded" flag. */ - - *pRPS++ = RPS_UPLOAD | RPS_DEBI; - /* Invoke shadow RAM upload. */ - - *pRPS++ = RPS_PAUSE | RPS_DEBI; - /* Wait for shadow upload to finish. */ - - /* Delay at least 10 microseconds for analog input settling. - * Instead of padding with NOPs, we use RPS_JUMP instructions - * here; this allows us to produce a longer delay than is - * possible with NOPs because each RPS_JUMP flushes the RPS' - * instruction prefetch pipeline. + local_ppl = (*ppl << 8) | (*ppl & 0x10 ? S626_GSEL_BIPOLAR5V : + S626_GSEL_BIPOLAR10V); + + /* Switch ADC analog gain. */ + /* Write DEBI command and address to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_GSEL; + /* Write DEBI immediate data to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + *rps++ = local_ppl; + /* Reset "shadow RAM uploaded" flag. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; + /* Select ADC analog input channel. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + /* Write DEBI command and address to shadow RAM. */ + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_ISEL; + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + /* Write DEBI immediate data to shadow RAM. */ + *rps++ = local_ppl; + /* Reset "shadow RAM uploaded" flag. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; + + /* + * Delay at least 10 microseconds for analog input settling. + * Instead of padding with NOPs, we use S626_RPS_JUMP + * instructions here; this allows us to produce a longer delay + * than is possible with NOPs because each S626_RPS_JUMP + * flushes the RPS' instruction prefetch pipeline. */ - JmpAdrs = - (uint32_t) devpriv->RPSBuf.PhysicalBase + - (uint32_t) ((unsigned long)pRPS - - (unsigned long)devpriv->RPSBuf.LogicalBase); - for (i = 0; i < (10 * RPSCLK_PER_US / 2); i++) { - JmpAdrs += 8; /* Repeat to implement time delay: */ - *pRPS++ = RPS_JUMP; /* Jump to next RPS instruction. */ - *pRPS++ = JmpAdrs; + jmp_adrs = + (uint32_t)devpriv->rps_buf.physical_base + + (uint32_t)((unsigned long)rps - + (unsigned long)devpriv-> + rps_buf.logical_base); + for (i = 0; i < (10 * S626_RPSCLK_PER_US / 2); i++) { + jmp_adrs += 8; /* Repeat to implement time delay: */ + /* Jump to next RPS instruction. */ + *rps++ = S626_RPS_JUMP; + *rps++ = jmp_adrs; } if (cmd != NULL && cmd->convert_src != TRIG_NOW) { - /* Wait for Start trigger. */ - *pRPS++ = RPS_PAUSE | RPS_SIGADC; - *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC; + /* Wait for Start trigger. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_SIGADC; + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; } - /* Start ADC by pulsing GPIO1. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* Begin ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_LO; - *pRPS++ = RPS_NOP; - /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* End ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_HI; - - /* Wait for ADC to complete (GPIO2 is asserted high when ADC not + /* Start ADC by pulsing GPIO1. */ + /* Begin ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_LO; + *rps++ = S626_RPS_NOP; + /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ + /* End ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_HI; + /* + * Wait for ADC to complete (GPIO2 is asserted high when ADC not * busy) and for data from previous conversion to shift into FB * BUFFER 1 register. */ - *pRPS++ = RPS_PAUSE | RPS_GPIO2; /* Wait for ADC done. */ - - /* Transfer ADC data from FB BUFFER 1 register to DMA buffer. */ - *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2); - *pRPS++ = - (uint32_t) devpriv->ANABuf.PhysicalBase + - (devpriv->AdcItems << 2); - - /* If this slot's EndOfPollList flag is set, all channels have */ - /* now been processed. */ - if (*ppl++ & EOPL) { - devpriv->AdcItems++; /* Adjust poll list item count. */ - break; /* Exit poll list processing loop. */ + /* Wait for ADC done. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_GPIO2; + + /* Transfer ADC data from FB BUFFER 1 register to DMA buffer. */ + *rps++ = S626_RPS_STREG | + (S626_BUGFIX_STREG(S626_P_FB_BUFFER1) >> 2); + *rps++ = (uint32_t)devpriv->ana_buf.physical_base + + (devpriv->adc_items << 2); + + /* + * If this slot's EndOfPollList flag is set, all channels have + * now been processed. + */ + if (*ppl++ & S626_EOPL) { + devpriv->adc_items++; /* Adjust poll list item count. */ + break; /* Exit poll list processing loop. */ } } - /* VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the + /* + * VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the * ADC to stabilize for 2 microseconds before starting the final * (dummy) conversion. This delay is necessary to allow sufficient * time between last conversion finished and the start of the dummy * conversion. Without this delay, the last conversion's data value * is sometimes set to the previous conversion's data value. */ - for (n = 0; n < (2 * RPSCLK_PER_US); n++) - *pRPS++ = RPS_NOP; + for (n = 0; n < (2 * S626_RPSCLK_PER_US); n++) + *rps++ = S626_RPS_NOP; - /* Start a dummy conversion to cause the data from the last + /* + * Start a dummy conversion to cause the data from the last * conversion of interest to be shifted in. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* Begin ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_LO; - *pRPS++ = RPS_NOP; + /* Begin ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_LO; + *rps++ = S626_RPS_NOP; /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* End ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_HI; + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); /* End ADC Start pulse. */ + *rps++ = S626_GPIO_BASE | S626_GPIO1_HI; - /* Wait for the data from the last conversion of interest to arrive + /* + * Wait for the data from the last conversion of interest to arrive * in FB BUFFER 1 register. */ - *pRPS++ = RPS_PAUSE | RPS_GPIO2; /* Wait for ADC done. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_GPIO2; /* Wait for ADC done. */ - /* Transfer final ADC data from FB BUFFER 1 register to DMA buffer. */ - *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2); /* */ - *pRPS++ = - (uint32_t) devpriv->ANABuf.PhysicalBase + (devpriv->AdcItems << 2); + /* Transfer final ADC data from FB BUFFER 1 register to DMA buffer. */ + *rps++ = S626_RPS_STREG | (S626_BUGFIX_STREG(S626_P_FB_BUFFER1) >> 2); + *rps++ = (uint32_t)devpriv->ana_buf.physical_base + + (devpriv->adc_items << 2); - /* Indicate ADC scan loop is finished. */ - /* *pRPS++= RPS_CLRSIGNAL | RPS_SIGADC ; // Signal ReadADC() that scan is done. */ + /* Indicate ADC scan loop is finished. */ + /* Signal ReadADC() that scan is done. */ + /* *rps++= S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; */ /* invoke interrupt */ - if (devpriv->ai_cmd_running == 1) { - *pRPS++ = RPS_IRQ; - } - /* Restart RPS program at its beginning. */ - *pRPS++ = RPS_JUMP; /* Branch to start of RPS program. */ - *pRPS++ = (uint32_t) devpriv->RPSBuf.PhysicalBase; + if (devpriv->ai_cmd_running == 1) + *rps++ = S626_RPS_IRQ; - /* End of RPS program build */ + /* Restart RPS program at its beginning. */ + *rps++ = S626_RPS_JUMP; /* Branch to start of RPS program. */ + *rps++ = (uint32_t)devpriv->rps_buf.physical_base; + + /* End of RPS program build */ } #ifdef unused_code @@ -1111,14 +1834,14 @@ static int s626_ai_rinsn(struct comedi_device *dev, unsigned int *data) { struct s626_private *devpriv = dev->private; - register uint8_t i; - register int32_t *readaddr; + uint8_t i; + int32_t *readaddr; /* Trigger ADC scan loop start */ - s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); /* Wait until ADC scan loop is finished (RPS Signal 0 reset) */ - while (s626_mc_test(dev, MC2_ADC_RPS, P_MC2)) + while (s626_mc_test(dev, S626_MC2_ADC_RPS, S626_P_MC2)) ; /* @@ -1126,13 +1849,13 @@ static int s626_ai_rinsn(struct comedi_device *dev, * first uint16_t in the buffer because it contains junk data from * the final ADC of the previous poll list scan. */ - readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1; + readaddr = (uint32_t *)devpriv->ana_buf.logical_base + 1; /* * Convert ADC data to 16-bit integer values and * copy to application buffer. */ - for (i = 0; i < devpriv->AdcItems; i++) { + for (i = 0; i < devpriv->adc_items; i++) { *data = s626_ai_reg_to_uint(*readaddr++); data++; } @@ -1148,55 +1871,61 @@ static int s626_ai_insn_read(struct comedi_device *dev, struct s626_private *devpriv = dev->private; uint16_t chan = CR_CHAN(insn->chanspec); uint16_t range = CR_RANGE(insn->chanspec); - uint16_t AdcSpec = 0; - uint32_t GpioImage; - int tmp; + uint16_t adc_spec = 0; + uint32_t gpio_image; + uint32_t tmp; int n; - /* Convert application's ADC specification into form + /* + * Convert application's ADC specification into form * appropriate for register programming. */ if (range == 0) - AdcSpec = (chan << 8) | (GSEL_BIPOLAR5V); + adc_spec = (chan << 8) | (S626_GSEL_BIPOLAR5V); else - AdcSpec = (chan << 8) | (GSEL_BIPOLAR10V); + adc_spec = (chan << 8) | (S626_GSEL_BIPOLAR10V); - /* Switch ADC analog gain. */ - DEBIwrite(dev, LP_GSEL, AdcSpec); /* Set gain. */ + /* Switch ADC analog gain. */ + s626_debi_write(dev, S626_LP_GSEL, adc_spec); /* Set gain. */ - /* Select ADC analog input channel. */ - DEBIwrite(dev, LP_ISEL, AdcSpec); /* Select channel. */ + /* Select ADC analog input channel. */ + s626_debi_write(dev, S626_LP_ISEL, adc_spec); /* Select channel. */ for (n = 0; n < insn->n; n++) { - - /* Delay 10 microseconds for analog input settling. */ + /* Delay 10 microseconds for analog input settling. */ udelay(10); /* Start ADC by pulsing GPIO1 low */ - GpioImage = readl(devpriv->mmio + P_GPIO); + gpio_image = readl(devpriv->mmio + S626_P_GPIO); /* Assert ADC Start command */ - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); /* and stretch it out */ - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); /* Negate ADC Start command */ - writel(GpioImage | GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); - /* Wait for ADC to complete (GPIO2 is asserted high when */ - /* ADC not busy) and for data from previous conversion to */ - /* shift into FB BUFFER 1 register. */ + /* + * Wait for ADC to complete (GPIO2 is asserted high when + * ADC not busy) and for data from previous conversion to + * shift into FB BUFFER 1 register. + */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + P_PSR) & PSR_GPIO2)) + while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2)) ; /* Fetch ADC data */ if (n != 0) { - tmp = readl(devpriv->mmio + P_FB_BUFFER1); + tmp = readl(devpriv->mmio + S626_P_FB_BUFFER1); data[n - 1] = s626_ai_reg_to_uint(tmp); } - /* Allow the ADC to stabilize for 4 microseconds before + /* + * Allow the ADC to stabilize for 4 microseconds before * starting the next (final) conversion. This delay is * necessary to allow sufficient time between last * conversion finished and the start of the next @@ -1207,28 +1936,30 @@ static int s626_ai_insn_read(struct comedi_device *dev, udelay(4); } - /* Start a dummy conversion to cause the data from the - * previous conversion to be shifted in. */ - GpioImage = readl(devpriv->mmio + P_GPIO); + /* + * Start a dummy conversion to cause the data from the + * previous conversion to be shifted in. + */ + gpio_image = readl(devpriv->mmio + S626_P_GPIO); /* Assert ADC Start command */ - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); /* and stretch it out */ - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); - writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); /* Negate ADC Start command */ - writel(GpioImage | GPIO1_HI, devpriv->mmio + P_GPIO); + writel(gpio_image | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); - /* Wait for the data to arrive in FB BUFFER 1 register. */ + /* Wait for the data to arrive in FB BUFFER 1 register. */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + P_PSR) & PSR_GPIO2)) + while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2)) ; - /* Fetch ADC data from audio interface's input shift register. */ + /* Fetch ADC data from audio interface's input shift register. */ /* Fetch ADC data */ if (n != 0) { - tmp = readl(devpriv->mmio + P_FB_BUFFER1); + tmp = readl(devpriv->mmio + S626_P_FB_BUFFER1); data[n - 1] = s626_ai_reg_to_uint(tmp); } @@ -1237,17 +1968,16 @@ static int s626_ai_insn_read(struct comedi_device *dev, static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd) { - int n; for (n = 0; n < cmd->chanlist_len; n++) { - if (CR_RANGE((cmd->chanlist)[n]) == 0) - ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_5V); + if (CR_RANGE(cmd->chanlist[n]) == 0) + ppl[n] = CR_CHAN(cmd->chanlist[n]) | S626_RANGE_5V; else - ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_10V); + ppl[n] = CR_CHAN(cmd->chanlist[n]) | S626_RANGE_10V; } if (n != 0) - ppl[n - 1] |= EOPL; + ppl[n - 1] |= S626_EOPL; return n; } @@ -1259,18 +1989,20 @@ static int s626_ai_inttrig(struct comedi_device *dev, return -EINVAL; /* Start executing the RPS program */ - s626_mc_enable(dev, MC1_ERPS1, P_MC1); + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); s->async->inttrig = NULL; return 1; } -/* This function doesn't require a particular form, this is just what +/* + * This function doesn't require a particular form, this is just what * happens to be used in some of the drivers. It should convert ns * nanoseconds to a counter value suitable for programming the device. * Also, it should adjust ns so that it cooresponds to the actual time - * that the device will use. */ + * that the device will use. + */ static int s626_ns_to_timer(int *nanosec, int round_mode) { int divider, base; @@ -1294,68 +2026,76 @@ static int s626_ns_to_timer(int *nanosec, int round_mode) return divider - 1; } -static void s626_timer_load(struct comedi_device *dev, struct enc_private *k, - int tick) +static void s626_timer_load(struct comedi_device *dev, + const struct s626_enc_info *k, int tick) { - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_TIMER << BF_CLKSRC) | /* Operating mode is Timer. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - (CNTDIR_DOWN << BF_CLKPOL) | /* Count direction is Down. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); - uint16_t valueSrclatch = LATCHSRC_A_INDXA; - /* uint16_t enab=CLKENAB_ALWAYS; */ + uint16_t setup = + /* Preload upon index. */ + (S626_LOADSRC_INDX << S626_BF_LOADSRC) | + /* Disable hardware index. */ + (S626_INDXSRC_SOFT << S626_BF_INDXSRC) | + /* Operating mode is Timer. */ + (S626_CLKSRC_TIMER << S626_BF_CLKSRC) | + /* Active high clock. */ + (S626_CLKPOL_POS << S626_BF_CLKPOL) | + /* Count direction is Down. */ + (S626_CNTDIR_DOWN << S626_BF_CLKPOL) | + /* Clock multiplier is 1x. */ + (S626_CLKMULT_1X << S626_BF_CLKMULT) | + (S626_CLKENAB_INDEX << S626_BF_CLKENAB); + uint16_t value_latchsrc = S626_LATCHSRC_A_INDXA; + /* uint16_t enab = S626_CLKENAB_ALWAYS; */ - k->SetMode(dev, k, Setup, FALSE); + k->set_mode(dev, k, setup, false); - /* Set the preload register */ - Preload(dev, k, tick); + /* Set the preload register */ + s626_preload(dev, k, tick); - /* Software index pulse forces the preload register to load */ - /* into the counter */ - k->SetLoadTrig(dev, k, 0); - k->PulseIndex(dev, k); + /* + * Software index pulse forces the preload register to load + * into the counter + */ + k->set_load_trig(dev, k, 0); + k->pulse_index(dev, k); /* set reload on counter overflow */ - k->SetLoadTrig(dev, k, 1); + k->set_load_trig(dev, k, 1); /* set interrupt on overflow */ - k->SetIntSrc(dev, k, INTSRC_OVER); + k->set_int_src(dev, k, S626_INTSRC_OVER); - SetLatchSource(dev, k, valueSrclatch); - /* k->SetEnable(dev,k,(uint16_t)(enab != 0)); */ + s626_set_latch_source(dev, k, value_latchsrc); + /* k->set_enable(dev, k, (uint16_t)(enab != 0)); */ } -/* TO COMPLETE */ +/* TO COMPLETE */ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct s626_private *devpriv = dev->private; uint8_t ppl[16]; struct comedi_cmd *cmd = &s->async->cmd; - struct enc_private *k; + const struct s626_enc_info *k; int tick; if (devpriv->ai_cmd_running) { - printk(KERN_ERR "s626_ai_cmd: Another ai_cmd is running %d\n", - dev->minor); + dev_err(dev->class_dev, + "s626_ai_cmd: Another ai_cmd is running\n"); return -EBUSY; } /* disable interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* clear interrupt request */ - writel(IRQ_RPS1 | IRQ_GPIO3, devpriv->mmio + P_ISR); + writel(S626_IRQ_RPS1 | S626_IRQ_GPIO3, devpriv->mmio + S626_P_ISR); /* clear any pending interrupt */ s626_dio_clear_irq(dev); - /* s626_enc_clear_irq(dev); */ + /* s626_enc_clear_irq(dev); */ /* reset ai_cmd_running flag */ devpriv->ai_cmd_running = 0; - /* test if cmd is valid */ + /* test if cmd is valid */ if (cmd == NULL) return -EINVAL; @@ -1373,17 +2113,20 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_FOLLOW: break; case TRIG_TIMER: - /* set a conter to generate adc trigger at scan_begin_arg interval */ - k = &encpriv[5]; + /* + * set a counter to generate adc trigger at scan_begin_arg + * interval + */ + k = &s626_enc_chan_info[5]; tick = s626_ns_to_timer((int *)&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); /* load timer value and enable interrupt */ s626_timer_load(dev, k, tick); - k->SetEnable(dev, k, CLKENAB_ALWAYS); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); break; case TRIG_EXT: - /* set the digital line and interrupt for scan trigger */ + /* set the digital line and interrupt for scan trigger */ if (cmd->start_src != TRIG_EXT) s626_dio_set_irq(dev, cmd->scan_begin_arg); break; @@ -1393,52 +2136,53 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_NOW: break; case TRIG_TIMER: - /* set a conter to generate adc trigger at convert_arg interval */ - k = &encpriv[4]; + /* + * set a counter to generate adc trigger at convert_arg + * interval + */ + k = &s626_enc_chan_info[4]; tick = s626_ns_to_timer((int *)&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); /* load timer value and enable interrupt */ s626_timer_load(dev, k, tick); - k->SetEnable(dev, k, CLKENAB_INDEX); + k->set_enable(dev, k, S626_CLKENAB_INDEX); break; case TRIG_EXT: - /* set the digital line and interrupt for convert trigger */ - if (cmd->scan_begin_src != TRIG_EXT - && cmd->start_src == TRIG_EXT) + /* set the digital line and interrupt for convert trigger */ + if (cmd->scan_begin_src != TRIG_EXT && + cmd->start_src == TRIG_EXT) s626_dio_set_irq(dev, cmd->convert_arg); break; } switch (cmd->stop_src) { case TRIG_COUNT: - /* data arrives as one packet */ + /* data arrives as one packet */ devpriv->ai_sample_count = cmd->stop_arg; - devpriv->ai_continous = 0; + devpriv->ai_continuous = 0; break; case TRIG_NONE: - /* continous acquisition */ - devpriv->ai_continous = 1; + /* continuous acquisition */ + devpriv->ai_continuous = 1; devpriv->ai_sample_count = 1; break; } - ResetADC(dev, ppl); + s626_reset_adc(dev, ppl); switch (cmd->start_src) { case TRIG_NOW: /* Trigger ADC scan loop start */ - /* s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); */ + /* s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); */ /* Start executing the RPS program */ - s626_mc_enable(dev, MC1_ERPS1, P_MC1); - + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); s->async->inttrig = NULL; break; case TRIG_EXT: /* configure DIO channel for acquisition trigger */ s626_dio_set_irq(dev, cmd->start_arg); - s->async->inttrig = NULL; break; case TRIG_INT: @@ -1447,7 +2191,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* enable interrupt */ - writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->mmio + P_IER); + writel(S626_IRQ_GPIO3 | S626_IRQ_RPS1, devpriv->mmio + S626_P_IER); return 0; } @@ -1461,11 +2205,11 @@ static int s626_ai_cmdtest(struct comedi_device *dev, /* Step 1 : check if triggers are trivially valid */ err |= cfc_check_trigger_src(&cmd->start_src, - TRIG_NOW | TRIG_INT | TRIG_EXT); + TRIG_NOW | TRIG_INT | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW); + TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW); err |= cfc_check_trigger_src(&cmd->convert_src, - TRIG_TIMER | TRIG_EXT | TRIG_NOW); + TRIG_TIMER | TRIG_EXT | TRIG_NOW); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -1490,34 +2234,34 @@ static int s626_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); if (cmd->start_src == TRIG_EXT) err |= cfc_check_trigger_arg_max(&cmd->start_arg, 39); - if (cmd->scan_begin_src == TRIG_EXT) err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 39); - if (cmd->convert_src == TRIG_EXT) err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 39); -#define MAX_SPEED 200000 /* in nanoseconds */ -#define MIN_SPEED 2000000000 /* in nanoseconds */ +#define S626_MAX_SPEED 200000 /* in nanoseconds */ +#define S626_MIN_SPEED 2000000000 /* in nanoseconds */ if (cmd->scan_begin_src == TRIG_TIMER) { err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SPEED); + S626_MAX_SPEED); err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, - MIN_SPEED); + S626_MIN_SPEED); } else { /* external trigger */ /* should be level/edge, hi/lo specification here */ /* should specify multiple external triggers */ -/* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ + /* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ } if (cmd->convert_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, MIN_SPEED); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + S626_MAX_SPEED); + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, + S626_MIN_SPEED); } else { /* external trigger */ /* see above */ -/* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ + /* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ } err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); @@ -1546,10 +2290,10 @@ static int s626_ai_cmdtest(struct comedi_device *dev, if (tmp != cmd->convert_arg) err++; if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; + cmd->scan_begin_arg < cmd->convert_arg * + cmd->scan_end_arg) { + cmd->scan_begin_arg = cmd->convert_arg * + cmd->scan_end_arg; err++; } } @@ -1565,10 +2309,10 @@ static int s626_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) struct s626_private *devpriv = dev->private; /* Stop RPS program in case it is currently running */ - s626_mc_disable(dev, MC1_ERPS1, P_MC1); + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); /* disable master interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); devpriv->ai_cmd_running = 0; @@ -1588,7 +2332,7 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i]; dacdata -= (0x1fff); - SetDAC(dev, chan, dacdata); + s626_set_dac(dev, chan, dacdata); } return i; @@ -1606,7 +2350,9 @@ static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* *************** DIGITAL I/O FUNCTIONS *************** +/* *************** DIGITAL I/O FUNCTIONS *************** */ + +/* * All DIO functions address a group of DIO channels by means of * "group" argument. group may be 0, 1 or 2, which correspond to DIO * ports A, B and C, respectively. @@ -1616,19 +2362,19 @@ static void s626_dio_init(struct comedi_device *dev) { uint16_t group; - /* Prepare to treat writes to WRCapSel as capture disables. */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); + /* Prepare to treat writes to WRCapSel as capture disables. */ + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); - /* For each group of sixteen channels ... */ + /* For each group of sixteen channels ... */ for (group = 0; group < S626_DIO_BANKS; group++) { /* Disable all interrupts */ - DEBIwrite(dev, LP_WRINTSEL(group), 0); + s626_debi_write(dev, S626_LP_WRINTSEL(group), 0); /* Disable all event captures */ - DEBIwrite(dev, LP_WRCAPSEL(group), 0xffff); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), 0xffff); /* Init all DIOs to default edge polarity */ - DEBIwrite(dev, LP_WREDGSEL(group), 0); + s626_debi_write(dev, S626_LP_WREDGSEL(group), 0); /* Program all outputs to inactive state */ - DEBIwrite(dev, LP_WRDOUT(group), 0); + s626_debi_write(dev, S626_LP_WRDOUT(group), 0); } } @@ -1638,20 +2384,11 @@ static int s626_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { unsigned long group = (unsigned long)s->private; - unsigned long mask = data[0]; - unsigned long bits = data[1]; - - if (mask) { - /* Check if requested channels are configured for output */ - if ((s->io_bits & mask) != mask) - return -EIO; - s->state &= ~mask; - s->state |= (bits & mask); + if (comedi_dio_update_state(s, data)) + s626_debi_write(dev, S626_LP_WRDOUT(group), s->state); - DEBIwrite(dev, LP_WRDOUT(group), s->state); - } - data[1] = DEBIread(dev, LP_RDDIN(group)); + data[1] = s626_debi_read(dev, S626_LP_RDDIN(group)); return insn->n; } @@ -1668,42 +2405,50 @@ static int s626_dio_insn_config(struct comedi_device *dev, if (ret) return ret; - DEBIwrite(dev, LP_WRDOUT(group), s->io_bits); + s626_debi_write(dev, S626_LP_WRDOUT(group), s->io_bits); return insn->n; } -/* Now this function initializes the value of the counter (data[0]) - and set the subdevice. To complete with trigger and interrupt - configuration */ -/* FIXME: data[0] is supposed to be an INSN_CONFIG_xxx constant indicating +/* + * Now this function initializes the value of the counter (data[0]) + * and set the subdevice. To complete with trigger and interrupt + * configuration. + * + * FIXME: data[0] is supposed to be an INSN_CONFIG_xxx constant indicating * what is being configured, but this function appears to be using data[0] - * as a variable. */ + * as a variable. + */ static int s626_enc_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_COUNTER << BF_CLKSRC) | /* Operating mode is Counter. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - /* ( CNTDIR_UP << BF_CLKPOL ) | // Count direction is Down. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); - /* uint16_t DisableIntSrc=TRUE; */ - /* uint32_t Preloadvalue; //Counter initial value */ - uint16_t valueSrclatch = LATCHSRC_AB_READ; - uint16_t enab = CLKENAB_ALWAYS; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; - - /* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ - - k->SetMode(dev, k, Setup, TRUE); - Preload(dev, k, data[0]); - k->PulseIndex(dev, k); - SetLatchSource(dev, k, valueSrclatch); - k->SetEnable(dev, k, (uint16_t) (enab != 0)); + uint16_t setup = + /* Preload upon index. */ + (S626_LOADSRC_INDX << S626_BF_LOADSRC) | + /* Disable hardware index. */ + (S626_INDXSRC_SOFT << S626_BF_INDXSRC) | + /* Operating mode is Counter. */ + (S626_CLKSRC_COUNTER << S626_BF_CLKSRC) | + /* Active high clock. */ + (S626_CLKPOL_POS << S626_BF_CLKPOL) | + /* Clock multiplier is 1x. */ + (S626_CLKMULT_1X << S626_BF_CLKMULT) | + (S626_CLKENAB_INDEX << S626_BF_CLKENAB); + /* uint16_t disable_int_src = true; */ + /* uint32_t Preloadvalue; //Counter initial value */ + uint16_t value_latchsrc = S626_LATCHSRC_AB_READ; + uint16_t enab = S626_CLKENAB_ALWAYS; + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; + + /* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ + + k->set_mode(dev, k, setup, true); + s626_preload(dev, k, data[0]); + k->pulse_index(dev, k); + s626_set_latch_source(dev, k, value_latchsrc); + k->set_enable(dev, k, (enab != 0)); return insn->n; } @@ -1712,12 +2457,12 @@ static int s626_enc_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; for (n = 0; n < insn->n; n++) - data[n] = ReadLatch(dev, k); + data[n] = s626_read_latch(dev, k); return n; } @@ -1726,31 +2471,32 @@ static int s626_enc_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; + /* Set the preload register */ + s626_preload(dev, k, data[0]); - /* Set the preload register */ - Preload(dev, k, data[0]); - - /* Software index pulse forces the preload register to load */ - /* into the counter */ - k->SetLoadTrig(dev, k, 0); - k->PulseIndex(dev, k); - k->SetLoadTrig(dev, k, 2); + /* + * Software index pulse forces the preload register to load + * into the counter + */ + k->set_load_trig(dev, k, 0); + k->pulse_index(dev, k); + k->set_load_trig(dev, k, 2); return 1; } -static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage) +static void s626_write_misc2(struct comedi_device *dev, uint16_t new_image) { - DEBIwrite(dev, LP_MISC1, MISC1_WENABLE); /* enab writes to */ - /* MISC2 register. */ - DEBIwrite(dev, LP_WRMISC2, NewImage); /* Write new image to MISC2. */ - DEBIwrite(dev, LP_MISC1, MISC1_WDISABLE); /* Disable writes to MISC2. */ + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_WENABLE); + s626_debi_write(dev, S626_LP_WRMISC2, new_image); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_WDISABLE); } -static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma, - size_t bsize) +static void s626_close_dma_b(struct comedi_device *dev, + struct s626_buffer_dma *pdma, size_t bsize) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); void *vbptr; @@ -1758,554 +2504,46 @@ static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma, if (pdma == NULL) return; - /* find the matching allocation from the board struct */ - vbptr = pdma->LogicalBase; - vpptr = pdma->PhysicalBase; + /* find the matching allocation from the board struct */ + vbptr = pdma->logical_base; + vpptr = pdma->physical_base; if (vbptr) { pci_free_consistent(pcidev, bsize, vbptr, vpptr); - pdma->LogicalBase = NULL; - pdma->PhysicalBase = 0; + pdma->logical_base = NULL; + pdma->physical_base = 0; } } -/* ****** PRIVATE COUNTER FUNCTIONS ****** */ - -/* Reset a counter's index and overflow event capture flags. */ - -static void ResetCapFlags_A(struct comedi_device *dev, struct enc_private *k) -{ - DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL, - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A); -} - -static void ResetCapFlags_B(struct comedi_device *dev, struct enc_private *k) -{ - DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL, - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B); -} - -/* Return counter setup in a format (COUNTER_SETUP) that is consistent */ -/* for both A and B counters. */ - -static uint16_t GetMode_A(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t cra; - register uint16_t crb; - register uint16_t setup; - - /* Fetch CRA and CRB register images. */ - cra = DEBIread(dev, k->MyCRA); - crb = DEBIread(dev, k->MyCRB); - - /* Populate the standardized counter setup bit fields. Note: */ - /* IndexSrc is restricted to ENC_X or IndxPol. */ - setup = ((cra & STDMSK_LOADSRC) /* LoadSrc = LoadSrcA. */ - |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC) /* LatchSrc = LatchSrcA. */ - |((cra << (STDBIT_INTSRC - CRABIT_INTSRC_A)) & STDMSK_INTSRC) /* IntSrc = IntSrcA. */ - |((cra << (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))) & STDMSK_INDXSRC) /* IndxSrc = IndxSrcA<1>. */ - |((cra >> (CRABIT_INDXPOL_A - STDBIT_INDXPOL)) & STDMSK_INDXPOL) /* IndxPol = IndxPolA. */ - |((crb >> (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)) & STDMSK_CLKENAB)); /* ClkEnab = ClkEnabA. */ - - /* Adjust mode-dependent parameters. */ - if (cra & (2 << CRABIT_CLKSRC_A)) /* If Timer mode (ClkSrcA<1> == 1): */ - setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |((cra << (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) & STDMSK_CLKPOL) /* Set ClkPol to indicate count direction (ClkSrcA<0>). */ - |(MULT_X1 << STDBIT_CLKMULT)); /* ClkMult must be 1x in Timer mode. */ - - else /* If Counter mode (ClkSrcA<1> == 0): */ - setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC) /* Indicate Counter mode. */ - |((cra >> (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) & STDMSK_CLKPOL) /* Pass through ClkPol. */ - |(((cra & CRAMSK_CLKMULT_A) == (MULT_X0 << CRABIT_CLKMULT_A)) ? /* Force ClkMult to 1x if not legal, else pass through. */ - (MULT_X1 << STDBIT_CLKMULT) : - ((cra >> (CRABIT_CLKMULT_A - - STDBIT_CLKMULT)) & STDMSK_CLKMULT))); - - /* Return adjusted counter setup. */ - return setup; -} - -static uint16_t GetMode_B(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t cra; - register uint16_t crb; - register uint16_t setup; - - /* Fetch CRA and CRB register images. */ - cra = DEBIread(dev, k->MyCRA); - crb = DEBIread(dev, k->MyCRB); - - /* Populate the standardized counter setup bit fields. Note: */ - /* IndexSrc is restricted to ENC_X or IndxPol. */ - setup = (((crb << (STDBIT_INTSRC - CRBBIT_INTSRC_B)) & STDMSK_INTSRC) /* IntSrc = IntSrcB. */ - |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC) /* LatchSrc = LatchSrcB. */ - |((crb << (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)) & STDMSK_LOADSRC) /* LoadSrc = LoadSrcB. */ - |((crb << (STDBIT_INDXPOL - CRBBIT_INDXPOL_B)) & STDMSK_INDXPOL) /* IndxPol = IndxPolB. */ - |((crb >> (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) & STDMSK_CLKENAB) /* ClkEnab = ClkEnabB. */ - |((cra >> ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)) & STDMSK_INDXSRC)); /* IndxSrc = IndxSrcB<1>. */ - - /* Adjust mode-dependent parameters. */ - if ((crb & CRBMSK_CLKMULT_B) == (MULT_X0 << CRBBIT_CLKMULT_B)) /* If Extender mode (ClkMultB == MULT_X0): */ - setup |= ((CLKSRC_EXTENDER << STDBIT_CLKSRC) /* Indicate Extender mode. */ - |(MULT_X1 << STDBIT_CLKMULT) /* Indicate multiplier is 1x. */ - |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL)); /* Set ClkPol equal to Timer count direction (ClkSrcB<0>). */ - - else if (cra & (2 << CRABIT_CLKSRC_B)) /* If Timer mode (ClkSrcB<1> == 1): */ - setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |(MULT_X1 << STDBIT_CLKMULT) /* Indicate multiplier is 1x. */ - |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL)); /* Set ClkPol equal to Timer count direction (ClkSrcB<0>). */ - - else /* If Counter mode (ClkSrcB<1> == 0): */ - setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |((crb >> (CRBBIT_CLKMULT_B - STDBIT_CLKMULT)) & STDMSK_CLKMULT) /* Clock multiplier is passed through. */ - |((crb << (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) & STDMSK_CLKPOL)); /* Clock polarity is passed through. */ - - /* Return adjusted counter setup. */ - return setup; -} - -/* - * Set the operating mode for the specified counter. The setup - * parameter is treated as a COUNTER_SETUP data type. The following - * parameters are programmable (all other parms are ignored): ClkMult, - * ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc. - */ - -static void SetMode_A(struct comedi_device *dev, struct enc_private *k, - uint16_t Setup, uint16_t DisableIntSrc) -{ - struct s626_private *devpriv = dev->private; - register uint16_t cra; - register uint16_t crb; - register uint16_t setup = Setup; /* Cache the Standard Setup. */ - - /* Initialize CRA and CRB images. */ - cra = ((setup & CRAMSK_LOADSRC_A) /* Preload trigger is passed through. */ - |((setup & STDMSK_INDXSRC) >> (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1)))); /* IndexSrc is restricted to ENC_X or IndxPol. */ - - crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A /* Reset any pending CounterA event captures. */ - | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_A - STDBIT_CLKENAB))); /* Clock enable is passed through. */ - - /* Force IntSrc to Disabled if DisableIntSrc is asserted. */ - if (!DisableIntSrc) - cra |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC - - CRABIT_INTSRC_A)); - - /* Populate all mode-dependent attributes of CRA & CRB images. */ - switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) { - case CLKSRC_EXTENDER: /* Extender Mode: Force to Timer mode */ - /* (Extender valid only for B counters). */ - - case CLKSRC_TIMER: /* Timer Mode: */ - cra |= ((2 << CRABIT_CLKSRC_A) /* ClkSrcA<1> selects system clock */ - |((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) /* with count direction (ClkSrcA<0>) obtained from ClkPol. */ - |(1 << CRABIT_CLKPOL_A) /* ClkPolA behaves as always-on clock enable. */ - |(MULT_X1 << CRABIT_CLKMULT_A)); /* ClkMult must be 1x. */ - break; - - default: /* Counter Mode: */ - cra |= (CLKSRC_COUNTER /* Select ENC_C and ENC_D as clock/direction inputs. */ - | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) /* Clock polarity is passed through. */ - |(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ? /* Force multiplier to x1 if not legal, otherwise pass through. */ - (MULT_X1 << CRABIT_CLKMULT_A) : - ((setup & STDMSK_CLKMULT) << (CRABIT_CLKMULT_A - - STDBIT_CLKMULT)))); - } - - /* Force positive index polarity if IndxSrc is software-driven only, */ - /* otherwise pass it through. */ - if (~setup & STDMSK_INDXSRC) - cra |= ((setup & STDMSK_INDXPOL) << (CRABIT_INDXPOL_A - - STDBIT_INDXPOL)); - - /* If IntSrc has been forced to Disabled, update the MISC2 interrupt */ - /* enable mask to indicate the counter interrupt is disabled. */ - if (DisableIntSrc) - devpriv->CounterIntEnabs &= ~k->MyEventBits[3]; - - /* While retaining CounterB and LatchSrc configurations, program the */ - /* new counter operating mode. */ - DEBIreplace(dev, k->MyCRA, CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B, cra); - DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A), crb); -} - -static void SetMode_B(struct comedi_device *dev, struct enc_private *k, - uint16_t Setup, uint16_t DisableIntSrc) -{ - struct s626_private *devpriv = dev->private; - register uint16_t cra; - register uint16_t crb; - register uint16_t setup = Setup; /* Cache the Standard Setup. */ - - /* Initialize CRA and CRB images. */ - cra = ((setup & STDMSK_INDXSRC) << ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)); /* IndexSrc field is restricted to ENC_X or IndxPol. */ - - crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B /* Reset event captures and disable interrupts. */ - | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) /* Clock enable is passed through. */ - |((setup & STDMSK_LOADSRC) >> (STDBIT_LOADSRC - CRBBIT_LOADSRC_B))); /* Preload trigger source is passed through. */ - - /* Force IntSrc to Disabled if DisableIntSrc is asserted. */ - if (!DisableIntSrc) - crb |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC - - CRBBIT_INTSRC_B)); - - /* Populate all mode-dependent attributes of CRA & CRB images. */ - switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) { - case CLKSRC_TIMER: /* Timer Mode: */ - cra |= ((2 << CRABIT_CLKSRC_B) /* ClkSrcB<1> selects system clock */ - |((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL))); /* with direction (ClkSrcB<0>) obtained from ClkPol. */ - crb |= ((1 << CRBBIT_CLKPOL_B) /* ClkPolB behaves as always-on clock enable. */ - |(MULT_X1 << CRBBIT_CLKMULT_B)); /* ClkMultB must be 1x. */ - break; - - case CLKSRC_EXTENDER: /* Extender Mode: */ - cra |= ((2 << CRABIT_CLKSRC_B) /* ClkSrcB source is OverflowA (same as "timer") */ - |((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL))); /* with direction obtained from ClkPol. */ - crb |= ((1 << CRBBIT_CLKPOL_B) /* ClkPolB controls IndexB -- always set to active. */ - |(MULT_X0 << CRBBIT_CLKMULT_B)); /* ClkMultB selects OverflowA as the clock source. */ - break; - - default: /* Counter Mode: */ - cra |= (CLKSRC_COUNTER << CRABIT_CLKSRC_B); /* Select ENC_C and ENC_D as clock/direction inputs. */ - crb |= (((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) /* ClkPol is passed through. */ - |(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ? /* Force ClkMult to x1 if not legal, otherwise pass through. */ - (MULT_X1 << CRBBIT_CLKMULT_B) : - ((setup & STDMSK_CLKMULT) << (CRBBIT_CLKMULT_B - - STDBIT_CLKMULT)))); - } - - /* Force positive index polarity if IndxSrc is software-driven only, */ - /* otherwise pass it through. */ - if (~setup & STDMSK_INDXSRC) - crb |= ((setup & STDMSK_INDXPOL) >> (STDBIT_INDXPOL - - CRBBIT_INDXPOL_B)); - - /* If IntSrc has been forced to Disabled, update the MISC2 interrupt */ - /* enable mask to indicate the counter interrupt is disabled. */ - if (DisableIntSrc) - devpriv->CounterIntEnabs &= ~k->MyEventBits[3]; - - /* While retaining CounterA and LatchSrc configurations, program the */ - /* new counter operating mode. */ - DEBIreplace(dev, k->MyCRA, ~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B), cra); - DEBIreplace(dev, k->MyCRB, CRBMSK_CLKENAB_A | CRBMSK_LATCHSRC, crb); -} - -/* Return/set a counter's enable. enab: 0=always enabled, 1=enabled by index. */ - -static void SetEnable_A(struct comedi_device *dev, struct enc_private *k, - uint16_t enab) -{ - DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A), - enab << CRBBIT_CLKENAB_A); -} - -static void SetEnable_B(struct comedi_device *dev, struct enc_private *k, - uint16_t enab) -{ - DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B), - enab << CRBBIT_CLKENAB_B); -} - -static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_A) & 1; -} - -static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_B) & 1; -} - -/* - * static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k ) - * { - * return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3; - * } - */ - -/* - * Return/set the event that will trigger transfer of the preload - * register into the counter. 0=ThisCntr_Index, 1=ThisCntr_Overflow, - * 2=OverflowA (B counters only), 3=disabled. - */ - -static void SetLoadTrig_A(struct comedi_device *dev, struct enc_private *k, - uint16_t Trig) -{ - DEBIreplace(dev, k->MyCRA, ~CRAMSK_LOADSRC_A, - Trig << CRABIT_LOADSRC_A); -} - -static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k, - uint16_t Trig) -{ - DEBIreplace(dev, k->MyCRB, ~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL), - Trig << CRBBIT_LOADSRC_B); -} - -static uint16_t GetLoadTrig_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRA) >> CRABIT_LOADSRC_A) & 3; -} - -static uint16_t GetLoadTrig_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_LOADSRC_B) & 3; -} - -/* Return/set counter interrupt source and clear any captured - * index/overflow events. IntSource: 0=Disabled, 1=OverflowOnly, - * 2=IndexOnly, 3=IndexAndOverflow. - */ - -static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k, - uint16_t IntSource) -{ - struct s626_private *devpriv = dev->private; - - /* Reset any pending counter overflow or index captures. */ - DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL, - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A); - - /* Program counter interrupt source. */ - DEBIreplace(dev, k->MyCRA, ~CRAMSK_INTSRC_A, - IntSource << CRABIT_INTSRC_A); - - /* Update MISC2 interrupt enable mask. */ - devpriv->CounterIntEnabs = - (devpriv->CounterIntEnabs & ~k-> - MyEventBits[3]) | k->MyEventBits[IntSource]; -} - -static void SetIntSrc_B(struct comedi_device *dev, struct enc_private *k, - uint16_t IntSource) -{ - struct s626_private *devpriv = dev->private; - uint16_t crb; - - /* Cache writeable CRB register image. */ - crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL; - - /* Reset any pending counter overflow or index captures. */ - DEBIwrite(dev, k->MyCRB, - (uint16_t) (crb | CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B)); - - /* Program counter interrupt source. */ - DEBIwrite(dev, k->MyCRB, - (uint16_t) ((crb & ~CRBMSK_INTSRC_B) | (IntSource << - CRBBIT_INTSRC_B))); - - /* Update MISC2 interrupt enable mask. */ - devpriv->CounterIntEnabs = - (devpriv->CounterIntEnabs & ~k-> - MyEventBits[3]) | k->MyEventBits[IntSource]; -} - -static uint16_t GetIntSrc_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRA) >> CRABIT_INTSRC_A) & 3; -} - -static uint16_t GetIntSrc_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_INTSRC_B) & 3; -} - -/* Return/set the clock multiplier. */ - -/* static void SetClkMult(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKMULT ) | ( value << STDBIT_CLKMULT ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkMult(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKMULT ) & 3; */ -/* } */ - -/* Return/set the clock polarity. */ - -/* static void SetClkPol( struct comedi_device *dev,struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKPOL ) | ( value << STDBIT_CLKPOL ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkPol(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKPOL ) & 1; */ -/* } */ - -/* Return/set the clock source. */ - -/* static void SetClkSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKSRC ) | ( value << STDBIT_CLKSRC ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkSrc( struct comedi_device *dev,struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKSRC ) & 3; */ -/* } */ - -/* Return/set the index polarity. */ - -/* static void SetIndexPol(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXPOL ) | ( (value != 0) << STDBIT_INDXPOL ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetIndexPol(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_INDXPOL ) & 1; */ -/* } */ - -/* Return/set the index source. */ - -/* static void SetIndexSrc(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXSRC ) | ( (value != 0) << STDBIT_INDXSRC ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetIndexSrc(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_INDXSRC ) & 1; */ -/* } */ - -/* Generate an index pulse. */ - -static void PulseIndex_A(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t cra; - - cra = DEBIread(dev, k->MyCRA); /* Pulse index. */ - DEBIwrite(dev, k->MyCRA, (uint16_t) (cra ^ CRAMSK_INDXPOL_A)); - DEBIwrite(dev, k->MyCRA, cra); -} - -static void PulseIndex_B(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t crb; - - crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL; /* Pulse index. */ - DEBIwrite(dev, k->MyCRB, (uint16_t) (crb ^ CRBMSK_INDXPOL_B)); - DEBIwrite(dev, k->MyCRB, crb); -} - -static struct enc_private enc_private_data[] = { - { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR0A, - .MyCRB = LP_CR0B, - .MyLatchLsw = LP_CNTR0ALSW, - .MyEventBits = EVBITS(0), - }, { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR1A, - .MyCRB = LP_CR1B, - .MyLatchLsw = LP_CNTR1ALSW, - .MyEventBits = EVBITS(1), - }, { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR2A, - .MyCRB = LP_CR2B, - .MyLatchLsw = LP_CNTR2ALSW, - .MyEventBits = EVBITS(2), - }, { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR0A, - .MyCRB = LP_CR0B, - .MyLatchLsw = LP_CNTR0BLSW, - .MyEventBits = EVBITS(3), - }, { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR1A, - .MyCRB = LP_CR1B, - .MyLatchLsw = LP_CNTR1BLSW, - .MyEventBits = EVBITS(4), - }, { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR2A, - .MyCRB = LP_CR2B, - .MyLatchLsw = LP_CNTR2BLSW, - .MyEventBits = EVBITS(5), - }, -}; - -static void CountersInit(struct comedi_device *dev) +static void s626_counters_init(struct comedi_device *dev) { int chan; - struct enc_private *k; - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_COUNTER << BF_CLKSRC) | /* Operating mode is counter. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - (CNTDIR_UP << BF_CLKPOL) | /* Count direction is up. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); /* Enabled by index */ - - /* Disable all counter interrupts and clear any captured counter events. */ + const struct s626_enc_info *k; + uint16_t setup = + /* Preload upon index. */ + (S626_LOADSRC_INDX << S626_BF_LOADSRC) | + /* Disable hardware index. */ + (S626_INDXSRC_SOFT << S626_BF_INDXSRC) | + /* Operating mode is counter. */ + (S626_CLKSRC_COUNTER << S626_BF_CLKSRC) | + /* Active high clock. */ + (S626_CLKPOL_POS << S626_BF_CLKPOL) | + /* Count direction is up. */ + (S626_CNTDIR_UP << S626_BF_CLKPOL) | + /* Clock multiplier is 1x. */ + (S626_CLKMULT_1X << S626_BF_CLKMULT) | + /* Enabled by index */ + (S626_CLKENAB_INDEX << S626_BF_CLKENAB); + + /* + * Disable all counter interrupts and clear any captured counter events. + */ for (chan = 0; chan < S626_ENCODER_CHANNELS; chan++) { - k = &encpriv[chan]; - k->SetMode(dev, k, Setup, TRUE); - k->SetIntSrc(dev, k, 0); - k->ResetCapFlags(dev, k); - k->SetEnable(dev, k, CLKENAB_ALWAYS); + k = &s626_enc_chan_info[chan]; + k->set_mode(dev, k, setup, true); + k->set_int_src(dev, k, 0); + k->reset_cap_flags(dev, k); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); } } @@ -2316,17 +2554,17 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev) void *addr; dma_addr_t appdma; - addr = pci_alloc_consistent(pcidev, DMABUF_SIZE, &appdma); + addr = pci_alloc_consistent(pcidev, S626_DMABUF_SIZE, &appdma); if (!addr) return -ENOMEM; - devpriv->ANABuf.LogicalBase = addr; - devpriv->ANABuf.PhysicalBase = appdma; + devpriv->ana_buf.logical_base = addr; + devpriv->ana_buf.physical_base = appdma; - addr = pci_alloc_consistent(pcidev, DMABUF_SIZE, &appdma); + addr = pci_alloc_consistent(pcidev, S626_DMABUF_SIZE, &appdma); if (!addr) return -ENOMEM; - devpriv->RPSBuf.LogicalBase = addr; - devpriv->RPSBuf.PhysicalBase = appdma; + devpriv->rps_buf.logical_base = addr; + devpriv->rps_buf.physical_base = appdma; return 0; } @@ -2334,42 +2572,43 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev) static void s626_initialize(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; - dma_addr_t pPhysBuf; + dma_addr_t phys_buf; uint16_t chan; int i; /* Enable DEBI and audio pins, enable I2C interface */ - s626_mc_enable(dev, MC1_DEBI | MC1_AUDIO | MC1_I2C, P_MC1); + s626_mc_enable(dev, S626_MC1_DEBI | S626_MC1_AUDIO | S626_MC1_I2C, + S626_P_MC1); /* - * Configure DEBI operating mode + * Configure DEBI operating mode * - * Local bus is 16 bits wide - * Declare DEBI transfer timeout interval - * Set up byte lane steering - * Intel-compatible local bus (DEBI never times out) + * Local bus is 16 bits wide + * Declare DEBI transfer timeout interval + * Set up byte lane steering + * Intel-compatible local bus (DEBI never times out) */ - writel(DEBI_CFG_SLAVE16 | - (DEBI_TOUT << DEBI_CFG_TOUT_BIT) | - DEBI_SWAP | DEBI_CFG_INTEL, - devpriv->mmio + P_DEBICFG); + writel(S626_DEBI_CFG_SLAVE16 | + (S626_DEBI_TOUT << S626_DEBI_CFG_TOUT_BIT) | S626_DEBI_SWAP | + S626_DEBI_CFG_INTEL, devpriv->mmio + S626_P_DEBICFG); /* Disable MMU paging */ - writel(DEBI_PAGE_DISABLE, devpriv->mmio + P_DEBIPAGE); + writel(S626_DEBI_PAGE_DISABLE, devpriv->mmio + S626_P_DEBIPAGE); /* Init GPIO so that ADC Start* is negated */ - writel(GPIO_BASE | GPIO1_HI, devpriv->mmio + P_GPIO); + writel(S626_GPIO_BASE | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); /* I2C device address for onboard eeprom (revb) */ - devpriv->I2CAdrs = 0xA0; + devpriv->i2c_adrs = 0xA0; /* * Issue an I2C ABORT command to halt any I2C * operation in progress and reset BUSY flag. */ - writel(I2C_CLKSEL | I2C_ABORT, devpriv->mmio + P_I2CSTAT); - s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2); - while (!(readl(devpriv->mmio + P_MC2) & MC2_UPLD_IIC)) + writel(S626_I2C_CLKSEL | S626_I2C_ABORT, + devpriv->mmio + S626_P_I2CSTAT); + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + while (!(readl(devpriv->mmio + S626_P_MC2) & S626_MC2_UPLD_IIC)) ; /* @@ -2377,9 +2616,9 @@ static void s626_initialize(struct comedi_device *dev) * reg twice to reset all I2C error flags. */ for (i = 0; i < 2; i++) { - writel(I2C_CLKSEL, devpriv->mmio + P_I2CSTAT); - s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2); - while (!s626_mc_test(dev, MC2_UPLD_IIC, P_MC2)) + writel(S626_I2C_CLKSEL, devpriv->mmio + S626_P_I2CSTAT); + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + while (!s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2)) ; } @@ -2389,31 +2628,32 @@ static void s626_initialize(struct comedi_device *dev) * DAC data setup times are satisfied, enable DAC serial * clock out. */ - writel(ACON2_INIT, devpriv->mmio + P_ACON2); + writel(S626_ACON2_INIT, devpriv->mmio + S626_P_ACON2); /* * Set up TSL1 slot list, which is used to control the - * accumulation of ADC data: RSD1 = shift data in on SD1. - * SIB_A1 = store data uint8_t at next available location + * accumulation of ADC data: S626_RSD1 = shift data in on SD1. + * S626_SIB_A1 = store data uint8_t at next available location * in FB BUFFER1 register. */ - writel(RSD1 | SIB_A1, devpriv->mmio + P_TSL1); - writel(RSD1 | SIB_A1 | EOS, devpriv->mmio + P_TSL1 + 4); + writel(S626_RSD1 | S626_SIB_A1, devpriv->mmio + S626_P_TSL1); + writel(S626_RSD1 | S626_SIB_A1 | S626_EOS, + devpriv->mmio + S626_P_TSL1 + 4); /* Enable TSL1 slot list so that it executes all the time */ - writel(ACON1_ADCSTART, devpriv->mmio + P_ACON1); + writel(S626_ACON1_ADCSTART, devpriv->mmio + S626_P_ACON1); /* * Initialize RPS registers used for ADC */ /* Physical start of RPS program */ - writel((uint32_t)devpriv->RPSBuf.PhysicalBase, - devpriv->mmio + P_RPSADDR1); + writel((uint32_t)devpriv->rps_buf.physical_base, + devpriv->mmio + S626_P_RPSADDR1); /* RPS program performs no explicit mem writes */ - writel(0, devpriv->mmio + P_RPSPAGE1); + writel(0, devpriv->mmio + S626_P_RPSPAGE1); /* Disable RPS timeouts */ - writel(0, devpriv->mmio + P_RPS1_TOUT); + writel(0, devpriv->mmio + S626_P_RPS1_TOUT); #if 0 /* @@ -2425,38 +2665,37 @@ static void s626_initialize(struct comedi_device *dev) * because the SAA7146 ADC interface does not start up in * a defined state after a PCI reset. */ - { - uint8_t PollList; - uint16_t AdcData; - uint16_t StartVal; - uint16_t index; - unsigned int data[16]; + uint8_t poll_list; + uint16_t adc_data; + uint16_t start_val; + uint16_t index; + unsigned int data[16]; - /* Create a simple polling list for analog input channel 0 */ - PollList = EOPL; - ResetADC(dev, &PollList); + /* Create a simple polling list for analog input channel 0 */ + poll_list = S626_EOPL; + s626_reset_adc(dev, &poll_list); - /* Get initial ADC value */ - s626_ai_rinsn(dev, dev->subdevices, NULL, data); - StartVal = data[0]; - - /* - * VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. - * - * Invoke ADCs until the new ADC value differs from the initial - * value or a timeout occurs. The timeout protects against the - * possibility that the driver is restarting and the ADC data is a - * fixed value resulting from the applied ADC analog input being - * unusually quiet or at the rail. - */ - for (index = 0; index < 500; index++) { + /* Get initial ADC value */ s626_ai_rinsn(dev, dev->subdevices, NULL, data); - AdcData = data[0]; - if (AdcData != StartVal) - break; - } + start_val = data[0]; + /* + * VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED + * EXECUTION. + * + * Invoke ADCs until the new ADC value differs from the initial + * value or a timeout occurs. The timeout protects against the + * possibility that the driver is restarting and the ADC data is + * a fixed value resulting from the applied ADC analog input + * being unusually quiet or at the rail. + */ + for (index = 0; index < 500; index++) { + s626_ai_rinsn(dev, dev->subdevices, NULL, data); + adc_data = data[0]; + if (adc_data != start_val) + break; + } } #endif /* SAA7146 BUG WORKAROUND */ @@ -2469,7 +2708,7 @@ static void s626_initialize(struct comedi_device *dev) * burst length = 1 DWORD * threshold = 1 DWORD. */ - writel(0, devpriv->mmio + P_PCI_BT_A); + writel(0, devpriv->mmio + S626_P_PCI_BT_A); /* * Init Audio2's output DMA physical addresses. The protection @@ -2477,18 +2716,18 @@ static void s626_initialize(struct comedi_device *dev) * single DWORD will be transferred each time a DMA transfer is * enabled. */ - pPhysBuf = devpriv->ANABuf.PhysicalBase + - (DAC_WDMABUF_OS * sizeof(uint32_t)); - writel((uint32_t)pPhysBuf, devpriv->mmio + P_BASEA2_OUT); - writel((uint32_t)(pPhysBuf + sizeof(uint32_t)), - devpriv->mmio + P_PROTA2_OUT); + phys_buf = devpriv->ana_buf.physical_base + + (S626_DAC_WDMABUF_OS * sizeof(uint32_t)); + writel((uint32_t)phys_buf, devpriv->mmio + S626_P_BASEA2_OUT); + writel((uint32_t)(phys_buf + sizeof(uint32_t)), + devpriv->mmio + S626_P_PROTA2_OUT); /* * Cache Audio2's output DMA buffer logical address. This is * where DAC data is buffered for A2 output DMA transfers. */ - devpriv->pDacWBuf = (uint32_t *)devpriv->ANABuf.LogicalBase + - DAC_WDMABUF_OS; + devpriv->dac_wbuf = (uint32_t *)devpriv->ana_buf.logical_base + + S626_DAC_WDMABUF_OS; /* * Audio2's output channels does not use paging. The @@ -2496,7 +2735,7 @@ static void s626_initialize(struct comedi_device *dev) * DMAC will automatically halt and its PCI address pointer * will be reset when the protection address is reached. */ - writel(8, devpriv->mmio + P_PAGEA2_OUT); + writel(8, devpriv->mmio + S626_P_PAGEA2_OUT); /* * Initialize time slot list 2 (TSL2), which is used to control @@ -2511,7 +2750,8 @@ static void s626_initialize(struct comedi_device *dev) */ /* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2 */ - writel(XSD2 | RSD3 | SIB_A2 | EOS, devpriv->mmio + VECTPORT(0)); + writel(S626_XSD2 | S626_RSD3 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); /* * Initialize slot 1, which is constant. Slot 1 causes a @@ -2523,18 +2763,18 @@ static void s626_initialize(struct comedi_device *dev) */ /* Slot 1: Fetch DWORD from Audio2's output FIFO */ - writel(LF_A2, devpriv->mmio + VECTPORT(1)); + writel(S626_LF_A2, devpriv->mmio + S626_VECTPORT(1)); /* Start DAC's audio interface (TSL2) running */ - writel(ACON1_DACSTART, devpriv->mmio + P_ACON1); + writel(S626_ACON1_DACSTART, devpriv->mmio + S626_P_ACON1); /* * Init Trim DACs to calibrated values. Do it twice because the * SAA7146 audio channel does not always reset properly and * sometimes causes the first few TrimDAC writes to malfunction. */ - LoadTrimDACs(dev); - LoadTrimDACs(dev); + s626_load_trim_dacs(dev); + s626_load_trim_dacs(dev); /* * Manually init all gate array hardware in case this is a soft @@ -2549,10 +2789,10 @@ static void s626_initialize(struct comedi_device *dev) * polarity images. */ for (chan = 0; chan < S626_DAC_CHANNELS; chan++) - SetDAC(dev, chan, 0); + s626_set_dac(dev, chan, 0); /* Init counters */ - CountersInit(dev); + s626_counters_init(dev); /* * Without modifying the state of the Battery Backup enab, disable @@ -2560,8 +2800,8 @@ static void s626_initialize(struct comedi_device *dev) * standard DIO (vs. counter overflow) mode, disable the battery * charger, and reset the watchdog interval selector to zero. */ - WriteMISC2(dev, (uint16_t)(DEBIread(dev, LP_RDMISC2) & - MISC2_BATT_ENABLE)); + s626_write_misc2(dev, (s626_debi_read(dev, S626_LP_RDMISC2) & + S626_MISC2_BATT_ENABLE)); /* Initialize the digital I/O subsystem */ s626_dio_init(dev); @@ -2588,10 +2828,10 @@ static int s626_auto_attach(struct comedi_device *dev, return -ENOMEM; /* disable master interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* soft reset */ - writel(MC1_SOFT_RESET, devpriv->mmio + P_MC1); + writel(S626_MC1_SOFT_RESET, devpriv->mmio + S626_P_MC1); /* DMA FIXME DMA// */ @@ -2670,7 +2910,7 @@ static int s626_auto_attach(struct comedi_device *dev, s->io_bits = 0xffff; s->private = (void *)2; /* DIO group 2 */ s->range_table = &range_digital; - s->insn_config = s626_dio_insn_config; + s->insn_config = s626_dio_insn_config; s->insn_bits = s626_dio_insn_bits; s = &dev->subdevices[5]; @@ -2679,7 +2919,6 @@ static int s626_auto_attach(struct comedi_device *dev, s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL; s->n_chan = S626_ENCODER_CHANNELS; s->maxdata = 0xffffff; - s->private = enc_private_data; s->range_table = &range_unknown; s->insn_config = s626_enc_insn_config; s->insn_read = s626_enc_insn_read; @@ -2703,20 +2942,22 @@ static void s626_detach(struct comedi_device *dev) if (devpriv->mmio) { /* interrupt mask */ /* Disable master interrupt */ - writel(0, devpriv->mmio + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* Clear board's IRQ status flag */ - writel(IRQ_GPIO3 | IRQ_RPS1, - devpriv->mmio + P_ISR); + writel(S626_IRQ_GPIO3 | S626_IRQ_RPS1, + devpriv->mmio + S626_P_ISR); - /* Disable the watchdog timer and battery charger. */ - WriteMISC2(dev, 0); + /* Disable the watchdog timer and battery charger. */ + s626_write_misc2(dev, 0); /* Close all interfaces on 7146 device */ - writel(MC1_SHUTDOWN, devpriv->mmio + P_MC1); - writel(ACON1_BASE, devpriv->mmio + P_ACON1); + writel(S626_MC1_SHUTDOWN, devpriv->mmio + S626_P_MC1); + writel(S626_ACON1_BASE, devpriv->mmio + S626_P_ACON1); - CloseDMAB(dev, &devpriv->RPSBuf, DMABUF_SIZE); - CloseDMAB(dev, &devpriv->ANABuf, DMABUF_SIZE); + s626_close_dma_b(dev, &devpriv->rps_buf, + S626_DMABUF_SIZE); + s626_close_dma_b(dev, &devpriv->ana_buf, + S626_DMABUF_SIZE); } if (dev->irq) @@ -2746,8 +2987,8 @@ static int s626_pci_probe(struct pci_dev *dev, * Philips SAA7146 media/dvb based cards. */ static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = { - { PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, - PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, 0, 0, 0 }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, + 0x6000, 0x0272) }, { 0 } }; MODULE_DEVICE_TABLE(pci, s626_pci_table); diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h index a85e6bdcad07..9b6ab0d398d6 100644 --- a/drivers/staging/comedi/drivers/s626.h +++ b/drivers/staging/comedi/drivers/s626.h @@ -1,690 +1,606 @@ /* - comedi/drivers/s626.h - Sensoray s626 Comedi driver, header file - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - Based on Sensoray Model 626 Linux driver Version 0.2 - Copyright (C) 2002-2004 Sensoray Co., Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ - -/* - Driver: s626.o (s626.ko) - Description: Sensoray 626 driver - Devices: Sensoray s626 - Authors: Gianluca Palli <gpalli@deis.unibo.it>, - Updated: Thu, 12 Jul 2005 - Status: experimental - - Configuration Options: - analog input: - none - - analog output: - none - - digital channel: - s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels - supported configuration options: - INSN_CONFIG_DIO_QUERY - COMEDI_INPUT - COMEDI_OUTPUT - - encoder: - Every channel must be configured before reading. - - Example code - - insn.insn=INSN_CONFIG; // configuration instruction - insn.n=1; // number of operation (must be 1) - insn.data=&initialvalue; // initial value loaded into encoder - // during configuration - insn.subdev=5; // encoder subdevice - insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); // encoder_channel - // to configure - - comedi_do_insn(cf,&insn); // executing configuration -*/ - -#if !defined(TRUE) -#define TRUE (1) -#endif - -#if !defined(FALSE) -#define FALSE (0) -#endif - -#define S626_SIZE 0x0200 -#define DMABUF_SIZE 4096 /* 4k pages */ + * comedi/drivers/s626.h + * Sensoray s626 Comedi driver, header file + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * Based on Sensoray Model 626 Linux driver Version 0.2 + * Copyright (C) 2002-2004 Sensoray Co., Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef S626_H_INCLUDED +#define S626_H_INCLUDED + +#define S626_DMABUF_SIZE 4096 /* 4k pages */ #define S626_ADC_CHANNELS 16 #define S626_DAC_CHANNELS 4 #define S626_ENCODER_CHANNELS 6 #define S626_DIO_CHANNELS 48 -#define S626_DIO_BANKS 3 /* Number of DIO groups. */ -#define S626_DIO_EXTCHANS 40 /* Number of */ - /* extended-capability */ - /* DIO channels. */ - -#define NUM_TRIMDACS 12 /* Number of valid TrimDAC channels. */ - -/* PCI bus interface types. */ -#define INTEL 1 /* Intel bus type. */ -#define MOTOROLA 2 /* Motorola bus type. */ +#define S626_DIO_BANKS 3 /* Number of DIO groups. */ +#define S626_DIO_EXTCHANS 40 /* Number of extended-capability + * DIO channels. */ -#define PLATFORM INTEL /* *** SELECT PLATFORM TYPE *** */ +#define S626_NUM_TRIMDACS 12 /* Number of valid TrimDAC channels. */ -#define RANGE_5V 0x10 /* +/-5V range */ -#define RANGE_10V 0x00 /* +/-10V range */ +/* PCI bus interface types. */ +#define S626_INTEL 1 /* Intel bus type. */ +#define S626_MOTOROLA 2 /* Motorola bus type. */ -#define EOPL 0x80 /* End of ADC poll list marker. */ -#define GSEL_BIPOLAR5V 0x00F0 /* LP_GSEL setting for 5V bipolar range. */ -#define GSEL_BIPOLAR10V 0x00A0 /* LP_GSEL setting for 10V bipolar range. */ +#define S626_PLATFORM S626_INTEL /* *** SELECT PLATFORM TYPE *** */ -/* Error codes that must be visible to this base class. */ -#define ERR_ILLEGAL_PARM 0x00010000 /* Illegal function parameter value was specified. */ -#define ERR_I2C 0x00020000 /* I2C error. */ -#define ERR_COUNTERSETUP 0x00200000 /* Illegal setup specified for counter channel. */ -#define ERR_DEBI_TIMEOUT 0x00400000 /* DEBI transfer timed out. */ +#define S626_RANGE_5V 0x10 /* +/-5V range */ +#define S626_RANGE_10V 0x00 /* +/-10V range */ -/* Organization (physical order) and size (in DWORDs) of logical DMA buffers contained by ANA_DMABUF. */ -#define ADC_DMABUF_DWORDS 40 /* ADC DMA buffer must hold 16 samples, plus pre/post garbage samples. */ -#define DAC_WDMABUF_DWORDS 1 /* DAC output DMA buffer holds a single sample. */ +#define S626_EOPL 0x80 /* End of ADC poll list marker. */ +#define S626_GSEL_BIPOLAR5V 0x00F0 /* S626_LP_GSEL setting 5V bipolar. */ +#define S626_GSEL_BIPOLAR10V 0x00A0 /* S626_LP_GSEL setting 10V bipolar. */ -/* All remaining space in 4KB DMA buffer is available for the RPS1 program. */ +/* Error codes that must be visible to this base class. */ +#define S626_ERR_ILLEGAL_PARM 0x00010000 /* Illegal function parameter + * value was specified. */ +#define S626_ERR_I2C 0x00020000 /* I2C error. */ +#define S626_ERR_COUNTERSETUP 0x00200000 /* Illegal setup specified for + * counter channel. */ +#define S626_ERR_DEBI_TIMEOUT 0x00400000 /* DEBI transfer timed out. */ -/* Address offsets, in DWORDS, from base of DMA buffer. */ -#define DAC_WDMABUF_OS ADC_DMABUF_DWORDS - -/* Interrupt enab bit in ISR and IER. */ -#define IRQ_GPIO3 0x00000040 /* IRQ enable for GPIO3. */ -#define IRQ_RPS1 0x10000000 -#define ISR_AFOU 0x00000800 +/* + * Organization (physical order) and size (in DWORDs) of logical DMA buffers + * contained by ANA_DMABUF. + */ +#define S626_ADC_DMABUF_DWORDS 40 /* ADC DMA buffer must hold 16 samples, + * plus pre/post garbage samples. */ +#define S626_DAC_WDMABUF_DWORDS 1 /* DAC output DMA buffer holds a single + * sample. */ + +/* All remaining space in 4KB DMA buffer is available for the RPS1 program. */ + +/* Address offsets, in DWORDS, from base of DMA buffer. */ +#define S626_DAC_WDMABUF_OS S626_ADC_DMABUF_DWORDS + +/* Interrupt enable bit in ISR and IER. */ +#define S626_IRQ_GPIO3 0x00000040 /* IRQ enable for GPIO3. */ +#define S626_IRQ_RPS1 0x10000000 +#define S626_ISR_AFOU 0x00000800 /* Audio fifo under/overflow detected. */ -#define IRQ_COINT1A 0x0400 /* conter 1A overflow interrupt mask */ -#define IRQ_COINT1B 0x0800 /* conter 1B overflow interrupt mask */ -#define IRQ_COINT2A 0x1000 /* conter 2A overflow interrupt mask */ -#define IRQ_COINT2B 0x2000 /* conter 2B overflow interrupt mask */ -#define IRQ_COINT3A 0x4000 /* conter 3A overflow interrupt mask */ -#define IRQ_COINT3B 0x8000 /* conter 3B overflow interrupt mask */ - -/* RPS command codes. */ -#define RPS_CLRSIGNAL 0x00000000 /* CLEAR SIGNAL */ -#define RPS_SETSIGNAL 0x10000000 /* SET SIGNAL */ -#define RPS_NOP 0x00000000 /* NOP */ -#define RPS_PAUSE 0x20000000 /* PAUSE */ -#define RPS_UPLOAD 0x40000000 /* UPLOAD */ -#define RPS_JUMP 0x80000000 /* JUMP */ -#define RPS_LDREG 0x90000100 /* LDREG (1 uint32_t only) */ -#define RPS_STREG 0xA0000100 /* STREG (1 uint32_t only) */ -#define RPS_STOP 0x50000000 /* STOP */ -#define RPS_IRQ 0x60000000 /* IRQ */ - -#define RPS_LOGICAL_OR 0x08000000 /* Logical OR conditionals. */ -#define RPS_INVERT 0x04000000 /* Test for negated semaphores. */ -#define RPS_DEBI 0x00000002 /* DEBI done */ - -#define RPS_SIG0 0x00200000 /* RPS semaphore 0 (used by ADC). */ -#define RPS_SIG1 0x00400000 /* RPS semaphore 1 (used by DAC). */ -#define RPS_SIG2 0x00800000 /* RPS semaphore 2 (not used). */ -#define RPS_GPIO2 0x00080000 /* RPS GPIO2 */ -#define RPS_GPIO3 0x00100000 /* RPS GPIO3 */ - -#define RPS_SIGADC RPS_SIG0 /* Trigger/status for ADC's RPS program. */ -#define RPS_SIGDAC RPS_SIG1 /* Trigger/status for DAC's RPS program. */ - -/* RPS clock parameters. */ -#define RPSCLK_SCALAR 8 /* This is apparent ratio of PCI/RPS clks (undocumented!!). */ -#define RPSCLK_PER_US (33 / RPSCLK_SCALAR) /* Number of RPS clocks in one microsecond. */ - -/* Event counter source addresses. */ -#define SBA_RPS_A0 0x27 /* Time of RPS0 busy, in PCI clocks. */ - -/* GPIO constants. */ -#define GPIO_BASE 0x10004000 /* GPIO 0,2,3 = inputs, GPIO3 = IRQ; GPIO1 = out. */ -#define GPIO1_LO 0x00000000 /* GPIO1 set to LOW. */ -#define GPIO1_HI 0x00001000 /* GPIO1 set to HIGH. */ - -/* Primary Status Register (PSR) constants. */ -#define PSR_DEBI_E 0x00040000 /* DEBI event flag. */ -#define PSR_DEBI_S 0x00080000 /* DEBI status flag. */ -#define PSR_A2_IN 0x00008000 /* Audio output DMA2 protection address reached. */ -#define PSR_AFOU 0x00000800 /* Audio FIFO under/overflow detected. */ -#define PSR_GPIO2 0x00000020 /* GPIO2 input pin: 0=AdcBusy, 1=AdcIdle. */ -#define PSR_EC0S 0x00000001 /* Event counter 0 threshold reached. */ - -/* Secondary Status Register (SSR) constants. */ -#define SSR_AF2_OUT 0x00000200 /* Audio 2 output FIFO under/overflow detected. */ - -/* Master Control Register 1 (MC1) constants. */ -#define MC1_SOFT_RESET 0x80000000 /* Invoke 7146 soft reset. */ -#define MC1_SHUTDOWN 0x3FFF0000 /* Shut down all MC1-controlled enables. */ - -#define MC1_ERPS1 0x2000 /* enab/disable RPS task 1. */ -#define MC1_ERPS0 0x1000 /* enab/disable RPS task 0. */ -#define MC1_DEBI 0x0800 /* enab/disable DEBI pins. */ -#define MC1_AUDIO 0x0200 /* enab/disable audio port pins. */ -#define MC1_I2C 0x0100 /* enab/disable I2C interface. */ -#define MC1_A2OUT 0x0008 /* enab/disable transfer on A2 out. */ -#define MC1_A2IN 0x0004 /* enab/disable transfer on A2 in. */ -#define MC1_A1IN 0x0001 /* enab/disable transfer on A1 in. */ - -/* Master Control Register 2 (MC2) constants. */ -#define MC2_UPLD_DEBIq 0x00020002 /* Upload DEBI registers. */ -#define MC2_UPLD_IICq 0x00010001 /* Upload I2C registers. */ -#define MC2_RPSSIG2_ONq 0x20002000 /* Assert RPS_SIG2. */ -#define MC2_RPSSIG1_ONq 0x10001000 /* Assert RPS_SIG1. */ -#define MC2_RPSSIG0_ONq 0x08000800 /* Assert RPS_SIG0. */ -#define MC2_UPLD_DEBI_MASKq 0x00000002 /* Upload DEBI mask. */ -#define MC2_UPLD_IIC_MASKq 0x00000001 /* Upload I2C mask. */ -#define MC2_RPSSIG2_MASKq 0x00002000 /* RPS_SIG2 bit mask. */ -#define MC2_RPSSIG1_MASKq 0x00001000 /* RPS_SIG1 bit mask. */ -#define MC2_RPSSIG0_MASKq 0x00000800 /* RPS_SIG0 bit mask. */ - -#define MC2_DELAYTRIG_4USq MC2_RPSSIG1_ON -#define MC2_DELAYBUSY_4USq MC2_RPSSIG1_MASK - -#define MC2_DELAYTRIG_6USq MC2_RPSSIG2_ON -#define MC2_DELAYBUSY_6USq MC2_RPSSIG2_MASK - -#define MC2_UPLD_DEBI 0x0002 /* Upload DEBI. */ -#define MC2_UPLD_IIC 0x0001 /* Upload I2C. */ -#define MC2_RPSSIG2 0x2000 /* RPS signal 2 (not used). */ -#define MC2_RPSSIG1 0x1000 /* RPS signal 1 (DAC RPS busy). */ -#define MC2_RPSSIG0 0x0800 /* RPS signal 0 (ADC RPS busy). */ - -#define MC2_ADC_RPS MC2_RPSSIG0 /* ADC RPS busy. */ -#define MC2_DAC_RPS MC2_RPSSIG1 /* DAC RPS busy. */ - -/* ***** oldies ***** */ -#define MC2_UPLD_DEBIQ 0x00020002 /* Upload DEBI registers. */ -#define MC2_UPLD_IICQ 0x00010001 /* Upload I2C registers. */ - -/* PCI BUS (SAA7146) REGISTER ADDRESS OFFSETS */ -#define P_PCI_BT_A 0x004C /* Audio DMA burst/threshold control. */ -#define P_DEBICFG 0x007C /* DEBI configuration. */ -#define P_DEBICMD 0x0080 /* DEBI command. */ -#define P_DEBIPAGE 0x0084 /* DEBI page. */ -#define P_DEBIAD 0x0088 /* DEBI target address. */ -#define P_I2CCTRL 0x008C /* I2C control. */ -#define P_I2CSTAT 0x0090 /* I2C status. */ -#define P_BASEA2_IN 0x00AC /* Audio input 2 base physical DMAbuf +#define S626_IRQ_COINT1A 0x0400 /* counter 1A overflow interrupt mask */ +#define S626_IRQ_COINT1B 0x0800 /* counter 1B overflow interrupt mask */ +#define S626_IRQ_COINT2A 0x1000 /* counter 2A overflow interrupt mask */ +#define S626_IRQ_COINT2B 0x2000 /* counter 2B overflow interrupt mask */ +#define S626_IRQ_COINT3A 0x4000 /* counter 3A overflow interrupt mask */ +#define S626_IRQ_COINT3B 0x8000 /* counter 3B overflow interrupt mask */ + +/* RPS command codes. */ +#define S626_RPS_CLRSIGNAL 0x00000000 /* CLEAR SIGNAL */ +#define S626_RPS_SETSIGNAL 0x10000000 /* SET SIGNAL */ +#define S626_RPS_NOP 0x00000000 /* NOP */ +#define S626_RPS_PAUSE 0x20000000 /* PAUSE */ +#define S626_RPS_UPLOAD 0x40000000 /* UPLOAD */ +#define S626_RPS_JUMP 0x80000000 /* JUMP */ +#define S626_RPS_LDREG 0x90000100 /* LDREG (1 uint32_t only) */ +#define S626_RPS_STREG 0xA0000100 /* STREG (1 uint32_t only) */ +#define S626_RPS_STOP 0x50000000 /* STOP */ +#define S626_RPS_IRQ 0x60000000 /* IRQ */ + +#define S626_RPS_LOGICAL_OR 0x08000000 /* Logical OR conditionals. */ +#define S626_RPS_INVERT 0x04000000 /* Test for negated + * semaphores. */ +#define S626_RPS_DEBI 0x00000002 /* DEBI done */ + +#define S626_RPS_SIG0 0x00200000 /* RPS semaphore 0 + * (used by ADC). */ +#define S626_RPS_SIG1 0x00400000 /* RPS semaphore 1 + * (used by DAC). */ +#define S626_RPS_SIG2 0x00800000 /* RPS semaphore 2 + * (not used). */ +#define S626_RPS_GPIO2 0x00080000 /* RPS GPIO2 */ +#define S626_RPS_GPIO3 0x00100000 /* RPS GPIO3 */ + +#define S626_RPS_SIGADC S626_RPS_SIG0 /* Trigger/status for + * ADC's RPS program. */ +#define S626_RPS_SIGDAC S626_RPS_SIG1 /* Trigger/status for + * DAC's RPS program. */ + +/* RPS clock parameters. */ +#define S626_RPSCLK_SCALAR 8 /* This is apparent ratio of + * PCI/RPS clks (undocumented!!). */ +#define S626_RPSCLK_PER_US (33 / S626_RPSCLK_SCALAR) + /* Number of RPS clocks in one + * microsecond. */ + +/* Event counter source addresses. */ +#define S626_SBA_RPS_A0 0x27 /* Time of RPS0 busy, in PCI clocks. */ + +/* GPIO constants. */ +#define S626_GPIO_BASE 0x10004000 /* GPIO 0,2,3 = inputs, + * GPIO3 = IRQ; GPIO1 = out. */ +#define S626_GPIO1_LO 0x00000000 /* GPIO1 set to LOW. */ +#define S626_GPIO1_HI 0x00001000 /* GPIO1 set to HIGH. */ + +/* Primary Status Register (PSR) constants. */ +#define S626_PSR_DEBI_E 0x00040000 /* DEBI event flag. */ +#define S626_PSR_DEBI_S 0x00080000 /* DEBI status flag. */ +#define S626_PSR_A2_IN 0x00008000 /* Audio output DMA2 protection + * address reached. */ +#define S626_PSR_AFOU 0x00000800 /* Audio FIFO under/overflow + * detected. */ +#define S626_PSR_GPIO2 0x00000020 /* GPIO2 input pin: 0=AdcBusy, + * 1=AdcIdle. */ +#define S626_PSR_EC0S 0x00000001 /* Event counter 0 threshold + * reached. */ + +/* Secondary Status Register (SSR) constants. */ +#define S626_SSR_AF2_OUT 0x00000200 /* Audio 2 output FIFO + * under/overflow detected. */ + +/* Master Control Register 1 (MC1) constants. */ +#define S626_MC1_SOFT_RESET 0x80000000 /* Invoke 7146 soft reset. */ +#define S626_MC1_SHUTDOWN 0x3FFF0000 /* Shut down all MC1-controlled + * enables. */ + +#define S626_MC1_ERPS1 0x2000 /* Enab/disable RPS task 1. */ +#define S626_MC1_ERPS0 0x1000 /* Enab/disable RPS task 0. */ +#define S626_MC1_DEBI 0x0800 /* Enab/disable DEBI pins. */ +#define S626_MC1_AUDIO 0x0200 /* Enab/disable audio port pins. */ +#define S626_MC1_I2C 0x0100 /* Enab/disable I2C interface. */ +#define S626_MC1_A2OUT 0x0008 /* Enab/disable transfer on A2 out. */ +#define S626_MC1_A2IN 0x0004 /* Enab/disable transfer on A2 in. */ +#define S626_MC1_A1IN 0x0001 /* Enab/disable transfer on A1 in. */ + +/* Master Control Register 2 (MC2) constants. */ +#define S626_MC2_UPLD_DEBI 0x0002 /* Upload DEBI. */ +#define S626_MC2_UPLD_IIC 0x0001 /* Upload I2C. */ +#define S626_MC2_RPSSIG2 0x2000 /* RPS signal 2 (not used). */ +#define S626_MC2_RPSSIG1 0x1000 /* RPS signal 1 (DAC RPS busy). */ +#define S626_MC2_RPSSIG0 0x0800 /* RPS signal 0 (ADC RPS busy). */ + +#define S626_MC2_ADC_RPS S626_MC2_RPSSIG0 /* ADC RPS busy. */ +#define S626_MC2_DAC_RPS S626_MC2_RPSSIG1 /* DAC RPS busy. */ + +/* PCI BUS (SAA7146) REGISTER ADDRESS OFFSETS */ +#define S626_P_PCI_BT_A 0x004C /* Audio DMA burst/threshold control. */ +#define S626_P_DEBICFG 0x007C /* DEBI configuration. */ +#define S626_P_DEBICMD 0x0080 /* DEBI command. */ +#define S626_P_DEBIPAGE 0x0084 /* DEBI page. */ +#define S626_P_DEBIAD 0x0088 /* DEBI target address. */ +#define S626_P_I2CCTRL 0x008C /* I2C control. */ +#define S626_P_I2CSTAT 0x0090 /* I2C status. */ +#define S626_P_BASEA2_IN 0x00AC /* Audio input 2 base physical DMAbuf * address. */ -#define P_PROTA2_IN 0x00B0 /* Audio input 2 physical DMAbuf +#define S626_P_PROTA2_IN 0x00B0 /* Audio input 2 physical DMAbuf * protection address. */ -#define P_PAGEA2_IN 0x00B4 /* Audio input 2 paging attributes. */ -#define P_BASEA2_OUT 0x00B8 /* Audio output 2 base physical DMAbuf +#define S626_P_PAGEA2_IN 0x00B4 /* Audio input 2 paging attributes. */ +#define S626_P_BASEA2_OUT 0x00B8 /* Audio output 2 base physical DMAbuf * address. */ -#define P_PROTA2_OUT 0x00BC /* Audio output 2 physical DMAbuf +#define S626_P_PROTA2_OUT 0x00BC /* Audio output 2 physical DMAbuf * protection address. */ -#define P_PAGEA2_OUT 0x00C0 /* Audio output 2 paging attributes. */ -#define P_RPSPAGE0 0x00C4 /* RPS0 page. */ -#define P_RPSPAGE1 0x00C8 /* RPS1 page. */ -#define P_RPS0_TOUT 0x00D4 /* RPS0 time-out. */ -#define P_RPS1_TOUT 0x00D8 /* RPS1 time-out. */ -#define P_IER 0x00DC /* Interrupt enable. */ -#define P_GPIO 0x00E0 /* General-purpose I/O. */ -#define P_EC1SSR 0x00E4 /* Event counter set 1 source select. */ -#define P_ECT1R 0x00EC /* Event counter threshold set 1. */ -#define P_ACON1 0x00F4 /* Audio control 1. */ -#define P_ACON2 0x00F8 /* Audio control 2. */ -#define P_MC1 0x00FC /* Master control 1. */ -#define P_MC2 0x0100 /* Master control 2. */ -#define P_RPSADDR0 0x0104 /* RPS0 instruction pointer. */ -#define P_RPSADDR1 0x0108 /* RPS1 instruction pointer. */ -#define P_ISR 0x010C /* Interrupt status. */ -#define P_PSR 0x0110 /* Primary status. */ -#define P_SSR 0x0114 /* Secondary status. */ -#define P_EC1R 0x0118 /* Event counter set 1. */ -#define P_ADP4 0x0138 /* Logical audio DMA pointer of audio +#define S626_P_PAGEA2_OUT 0x00C0 /* Audio output 2 paging attributes. */ +#define S626_P_RPSPAGE0 0x00C4 /* RPS0 page. */ +#define S626_P_RPSPAGE1 0x00C8 /* RPS1 page. */ +#define S626_P_RPS0_TOUT 0x00D4 /* RPS0 time-out. */ +#define S626_P_RPS1_TOUT 0x00D8 /* RPS1 time-out. */ +#define S626_P_IER 0x00DC /* Interrupt enable. */ +#define S626_P_GPIO 0x00E0 /* General-purpose I/O. */ +#define S626_P_EC1SSR 0x00E4 /* Event counter set 1 source select. */ +#define S626_P_ECT1R 0x00EC /* Event counter threshold set 1. */ +#define S626_P_ACON1 0x00F4 /* Audio control 1. */ +#define S626_P_ACON2 0x00F8 /* Audio control 2. */ +#define S626_P_MC1 0x00FC /* Master control 1. */ +#define S626_P_MC2 0x0100 /* Master control 2. */ +#define S626_P_RPSADDR0 0x0104 /* RPS0 instruction pointer. */ +#define S626_P_RPSADDR1 0x0108 /* RPS1 instruction pointer. */ +#define S626_P_ISR 0x010C /* Interrupt status. */ +#define S626_P_PSR 0x0110 /* Primary status. */ +#define S626_P_SSR 0x0114 /* Secondary status. */ +#define S626_P_EC1R 0x0118 /* Event counter set 1. */ +#define S626_P_ADP4 0x0138 /* Logical audio DMA pointer of audio * input FIFO A2_IN. */ -#define P_FB_BUFFER1 0x0144 /* Audio feedback buffer 1. */ -#define P_FB_BUFFER2 0x0148 /* Audio feedback buffer 2. */ -#define P_TSL1 0x0180 /* Audio time slot list 1. */ -#define P_TSL2 0x01C0 /* Audio time slot list 2. */ +#define S626_P_FB_BUFFER1 0x0144 /* Audio feedback buffer 1. */ +#define S626_P_FB_BUFFER2 0x0148 /* Audio feedback buffer 2. */ +#define S626_P_TSL1 0x0180 /* Audio time slot list 1. */ +#define S626_P_TSL2 0x01C0 /* Audio time slot list 2. */ -/* LOCAL BUS (GATE ARRAY) REGISTER ADDRESS OFFSETS */ -/* Analog I/O registers: */ -#define LP_DACPOL 0x0082 /* Write DAC polarity. */ -#define LP_GSEL 0x0084 /* Write ADC gain. */ -#define LP_ISEL 0x0086 /* Write ADC channel select. */ +/* LOCAL BUS (GATE ARRAY) REGISTER ADDRESS OFFSETS */ +/* Analog I/O registers: */ +#define S626_LP_DACPOL 0x0082 /* Write DAC polarity. */ +#define S626_LP_GSEL 0x0084 /* Write ADC gain. */ +#define S626_LP_ISEL 0x0086 /* Write ADC channel select. */ /* Digital I/O registers */ -#define LP_RDDIN(x) (0x0040 + (x) * 0x10) /* R: digital input */ -#define LP_WRINTSEL(x) (0x0042 + (x) * 0x10) /* W: int enable */ -#define LP_WREDGSEL(x) (0x0044 + (x) * 0x10) /* W: edge selection */ -#define LP_WRCAPSEL(x) (0x0046 + (x) * 0x10) /* W: capture enable */ -#define LP_RDCAPFLG(x) (0x0048 + (x) * 0x10) /* R: edges captured */ -#define LP_WRDOUT(x) (0x0048 + (x) * 0x10) /* W: digital output */ -#define LP_RDINTSEL(x) (0x004a + (x) * 0x10) /* R: int enable */ -#define LP_RDEDGSEL(x) (0x004c + (x) * 0x10) /* R: edge selection */ -#define LP_RDCAPSEL(x) (0x004e + (x) * 0x10) /* R: capture enable */ - -/* Counter Registers (read/write): */ -#define LP_CR0A 0x0000 /* 0A setup register. */ -#define LP_CR0B 0x0002 /* 0B setup register. */ -#define LP_CR1A 0x0004 /* 1A setup register. */ -#define LP_CR1B 0x0006 /* 1B setup register. */ -#define LP_CR2A 0x0008 /* 2A setup register. */ -#define LP_CR2B 0x000A /* 2B setup register. */ - -/* Counter PreLoad (write) and Latch (read) Registers: */ -#define LP_CNTR0ALSW 0x000C /* 0A lsw. */ -#define LP_CNTR0AMSW 0x000E /* 0A msw. */ -#define LP_CNTR0BLSW 0x0010 /* 0B lsw. */ -#define LP_CNTR0BMSW 0x0012 /* 0B msw. */ -#define LP_CNTR1ALSW 0x0014 /* 1A lsw. */ -#define LP_CNTR1AMSW 0x0016 /* 1A msw. */ -#define LP_CNTR1BLSW 0x0018 /* 1B lsw. */ -#define LP_CNTR1BMSW 0x001A /* 1B msw. */ -#define LP_CNTR2ALSW 0x001C /* 2A lsw. */ -#define LP_CNTR2AMSW 0x001E /* 2A msw. */ -#define LP_CNTR2BLSW 0x0020 /* 2B lsw. */ -#define LP_CNTR2BMSW 0x0022 /* 2B msw. */ - -/* Miscellaneous Registers (read/write): */ -#define LP_MISC1 0x0088 /* Read/write Misc1. */ -#define LP_WRMISC2 0x0090 /* Write Misc2. */ -#define LP_RDMISC2 0x0082 /* Read Misc2. */ - -/* Bit masks for MISC1 register that are the same for reads and writes. */ -#define MISC1_WENABLE 0x8000 /* enab writes to MISC2 (except Clear +#define S626_LP_RDDIN(x) (0x0040 + (x) * 0x10) /* R: digital input */ +#define S626_LP_WRINTSEL(x) (0x0042 + (x) * 0x10) /* W: int enable */ +#define S626_LP_WREDGSEL(x) (0x0044 + (x) * 0x10) /* W: edge selection */ +#define S626_LP_WRCAPSEL(x) (0x0046 + (x) * 0x10) /* W: capture enable */ +#define S626_LP_RDCAPFLG(x) (0x0048 + (x) * 0x10) /* R: edges captured */ +#define S626_LP_WRDOUT(x) (0x0048 + (x) * 0x10) /* W: digital output */ +#define S626_LP_RDINTSEL(x) (0x004a + (x) * 0x10) /* R: int enable */ +#define S626_LP_RDEDGSEL(x) (0x004c + (x) * 0x10) /* R: edge selection */ +#define S626_LP_RDCAPSEL(x) (0x004e + (x) * 0x10) /* R: capture enable */ + +/* Counter Registers (read/write): */ +#define S626_LP_CR0A 0x0000 /* 0A setup register. */ +#define S626_LP_CR0B 0x0002 /* 0B setup register. */ +#define S626_LP_CR1A 0x0004 /* 1A setup register. */ +#define S626_LP_CR1B 0x0006 /* 1B setup register. */ +#define S626_LP_CR2A 0x0008 /* 2A setup register. */ +#define S626_LP_CR2B 0x000A /* 2B setup register. */ + +/* Counter PreLoad (write) and Latch (read) Registers: */ +#define S626_LP_CNTR0ALSW 0x000C /* 0A lsw. */ +#define S626_LP_CNTR0AMSW 0x000E /* 0A msw. */ +#define S626_LP_CNTR0BLSW 0x0010 /* 0B lsw. */ +#define S626_LP_CNTR0BMSW 0x0012 /* 0B msw. */ +#define S626_LP_CNTR1ALSW 0x0014 /* 1A lsw. */ +#define S626_LP_CNTR1AMSW 0x0016 /* 1A msw. */ +#define S626_LP_CNTR1BLSW 0x0018 /* 1B lsw. */ +#define S626_LP_CNTR1BMSW 0x001A /* 1B msw. */ +#define S626_LP_CNTR2ALSW 0x001C /* 2A lsw. */ +#define S626_LP_CNTR2AMSW 0x001E /* 2A msw. */ +#define S626_LP_CNTR2BLSW 0x0020 /* 2B lsw. */ +#define S626_LP_CNTR2BMSW 0x0022 /* 2B msw. */ + +/* Miscellaneous Registers (read/write): */ +#define S626_LP_MISC1 0x0088 /* Read/write Misc1. */ +#define S626_LP_WRMISC2 0x0090 /* Write Misc2. */ +#define S626_LP_RDMISC2 0x0082 /* Read Misc2. */ + +/* Bit masks for MISC1 register that are the same for reads and writes. */ +#define S626_MISC1_WENABLE 0x8000 /* enab writes to MISC2 (except Clear * Watchdog bit). */ -#define MISC1_WDISABLE 0x0000 /* Disable writes to MISC2. */ -#define MISC1_EDCAP 0x1000 /* enab edge capture on DIO chans - * specified by LP_WRCAPSELx. */ -#define MISC1_NOEDCAP 0x0000 /* Disable edge capture on specified +#define S626_MISC1_WDISABLE 0x0000 /* Disable writes to MISC2. */ +#define S626_MISC1_EDCAP 0x1000 /* Enable edge capture on DIO chans + * specified by S626_LP_WRCAPSELx. */ +#define S626_MISC1_NOEDCAP 0x0000 /* Disable edge capture on specified * DIO chans. */ -/* Bit masks for MISC1 register reads. */ -#define RDMISC1_WDTIMEOUT 0x4000 /* Watchdog timer timed out. */ - -/* Bit masks for MISC2 register writes. */ -#define WRMISC2_WDCLEAR 0x8000 /* Reset watchdog timer to zero. */ -#define WRMISC2_CHARGE_ENABLE 0x4000 /* enab battery trickle charging. */ - -/* Bit masks for MISC2 register that are the same for reads and writes. */ -#define MISC2_BATT_ENABLE 0x0008 /* Backup battery enable. */ -#define MISC2_WDENABLE 0x0004 /* Watchdog timer enable. */ -#define MISC2_WDPERIOD_MASK 0x0003 /* Watchdog interval */ - /* select mask. */ - -/* Bit masks for ACON1 register. */ -#define A2_RUN 0x40000000 /* Run A2 based on TSL2. */ -#define A1_RUN 0x20000000 /* Run A1 based on TSL1. */ -#define A1_SWAP 0x00200000 /* Use big-endian for A1. */ -#define A2_SWAP 0x00100000 /* Use big-endian for A2. */ -#define WS_MODES 0x00019999 /* WS0 = TSL1 trigger */ - /* input, WS1-WS4 = */ - /* CS* outputs. */ - -#if PLATFORM == INTEL /* Base ACON1 config: always run A1 based - * on TSL1. */ -#define ACON1_BASE (WS_MODES | A1_RUN) -#elif PLATFORM == MOTOROLA -#define ACON1_BASE (WS_MODES | A1_RUN | A1_SWAP | A2_SWAP) +/* Bit masks for MISC1 register reads. */ +#define S626_RDMISC1_WDTIMEOUT 0x4000 /* Watchdog timer timed out. */ + +/* Bit masks for MISC2 register writes. */ +#define S626_WRMISC2_WDCLEAR 0x8000 /* Reset watchdog timer to zero. */ +#define S626_WRMISC2_CHARGE_ENABLE 0x4000 /* Enable battery trickle charging. */ + +/* Bit masks for MISC2 register that are the same for reads and writes. */ +#define S626_MISC2_BATT_ENABLE 0x0008 /* Backup battery enable. */ +#define S626_MISC2_WDENABLE 0x0004 /* Watchdog timer enable. */ +#define S626_MISC2_WDPERIOD_MASK 0x0003 /* Watchdog interval select mask. */ + +/* Bit masks for ACON1 register. */ +#define S626_A2_RUN 0x40000000 /* Run A2 based on TSL2. */ +#define S626_A1_RUN 0x20000000 /* Run A1 based on TSL1. */ +#define S626_A1_SWAP 0x00200000 /* Use big-endian for A1. */ +#define S626_A2_SWAP 0x00100000 /* Use big-endian for A2. */ +#define S626_WS_MODES 0x00019999 /* WS0 = TSL1 trigger input, + * WS1-WS4 = CS* outputs. */ + +#if S626_PLATFORM == S626_INTEL /* Base ACON1 config: always run + * A1 based on TSL1. */ +#define S626_ACON1_BASE (S626_WS_MODES | S626_A1_RUN) +#elif S626_PLATFORM == S626_MOTOROLA +#define S626_ACON1_BASE \ + (S626_WS_MODES | S626_A1_RUN | S626_A1_SWAP | S626_A2_SWAP) #endif -#define ACON1_ADCSTART ACON1_BASE /* Start ADC: run A1 - * based on TSL1. */ -#define ACON1_DACSTART (ACON1_BASE | A2_RUN) +#define S626_ACON1_ADCSTART S626_ACON1_BASE /* Start ADC: run A1 + * based on TSL1. */ +#define S626_ACON1_DACSTART (S626_ACON1_BASE | S626_A2_RUN) /* Start transmit to DAC: run A2 based on TSL2. */ -#define ACON1_DACSTOP ACON1_BASE /* Halt A2. */ - -/* Bit masks for ACON2 register. */ -#define A1_CLKSRC_BCLK1 0x00000000 /* A1 bit rate = BCLK1 (ADC). */ -#define A2_CLKSRC_X1 0x00800000 /* A2 bit rate = ACLK/1 (DACs). */ -#define A2_CLKSRC_X2 0x00C00000 /* A2 bit rate = ACLK/2 (DACs). */ -#define A2_CLKSRC_X4 0x01400000 /* A2 bit rate = ACLK/4 (DACs). */ -#define INVERT_BCLK2 0x00100000 /* Invert BCLK2 (DACs). */ -#define BCLK2_OE 0x00040000 /* enab BCLK2 (DACs). */ -#define ACON2_XORMASK 0x000C0000 /* XOR mask for ACON2 */ - /* active-low bits. */ - -#define ACON2_INIT (ACON2_XORMASK ^ (A1_CLKSRC_BCLK1 | A2_CLKSRC_X2 | INVERT_BCLK2 | BCLK2_OE)) - -/* Bit masks for timeslot records. */ -#define WS1 0x40000000 /* WS output to assert. */ -#define WS2 0x20000000 -#define WS3 0x10000000 -#define WS4 0x08000000 -#define RSD1 0x01000000 /* Shift A1 data in on SD1. */ -#define SDW_A1 0x00800000 /* Store rcv'd char at next - * char slot of DWORD1 buffer. */ -#define SIB_A1 0x00400000 /* Store rcv'd char at next +#define S626_ACON1_DACSTOP S626_ACON1_BASE /* Halt A2. */ + +/* Bit masks for ACON2 register. */ +#define S626_A1_CLKSRC_BCLK1 0x00000000 /* A1 bit rate = BCLK1 (ADC). */ +#define S626_A2_CLKSRC_X1 0x00800000 /* A2 bit rate = ACLK/1 + * (DACs). */ +#define S626_A2_CLKSRC_X2 0x00C00000 /* A2 bit rate = ACLK/2 + * (DACs). */ +#define S626_A2_CLKSRC_X4 0x01400000 /* A2 bit rate = ACLK/4 + * (DACs). */ +#define S626_INVERT_BCLK2 0x00100000 /* Invert BCLK2 (DACs). */ +#define S626_BCLK2_OE 0x00040000 /* Enable BCLK2 (DACs). */ +#define S626_ACON2_XORMASK 0x000C0000 /* XOR mask for ACON2 + * active-low bits. */ + +#define S626_ACON2_INIT (S626_ACON2_XORMASK ^ \ + (S626_A1_CLKSRC_BCLK1 | S626_A2_CLKSRC_X2 | \ + S626_INVERT_BCLK2 | S626_BCLK2_OE)) + +/* Bit masks for timeslot records. */ +#define S626_WS1 0x40000000 /* WS output to assert. */ +#define S626_WS2 0x20000000 +#define S626_WS3 0x10000000 +#define S626_WS4 0x08000000 +#define S626_RSD1 0x01000000 /* Shift A1 data in on SD1. */ +#define S626_SDW_A1 0x00800000 /* Store rcv'd char at next char + * slot of DWORD1 buffer. */ +#define S626_SIB_A1 0x00400000 /* Store rcv'd char at next * char slot of FB1 buffer. */ -#define SF_A1 0x00200000 /* Write unsigned long +#define S626_SF_A1 0x00200000 /* Write unsigned long * buffer to input FIFO. */ /* Select parallel-to-serial converter's data source: */ -#define XFIFO_0 0x00000000 /* Data fifo byte 0. */ -#define XFIFO_1 0x00000010 /* Data fifo byte 1. */ -#define XFIFO_2 0x00000020 /* Data fifo byte 2. */ -#define XFIFO_3 0x00000030 /* Data fifo byte 3. */ -#define XFB0 0x00000040 /* FB_BUFFER byte 0. */ -#define XFB1 0x00000050 /* FB_BUFFER byte 1. */ -#define XFB2 0x00000060 /* FB_BUFFER byte 2. */ -#define XFB3 0x00000070 /* FB_BUFFER byte 3. */ -#define SIB_A2 0x00000200 /* Store next dword from A2's - * input shifter to FB2 buffer. */ -#define SF_A2 0x00000100 /* Store next dword from A2's +#define S626_XFIFO_0 0x00000000 /* Data fifo byte 0. */ +#define S626_XFIFO_1 0x00000010 /* Data fifo byte 1. */ +#define S626_XFIFO_2 0x00000020 /* Data fifo byte 2. */ +#define S626_XFIFO_3 0x00000030 /* Data fifo byte 3. */ +#define S626_XFB0 0x00000040 /* FB_BUFFER byte 0. */ +#define S626_XFB1 0x00000050 /* FB_BUFFER byte 1. */ +#define S626_XFB2 0x00000060 /* FB_BUFFER byte 2. */ +#define S626_XFB3 0x00000070 /* FB_BUFFER byte 3. */ +#define S626_SIB_A2 0x00000200 /* Store next dword from A2's + * input shifter to FB2 + * buffer. */ +#define S626_SF_A2 0x00000100 /* Store next dword from A2's * input shifter to its input * fifo. */ -#define LF_A2 0x00000080 /* Load next dword from A2's +#define S626_LF_A2 0x00000080 /* Load next dword from A2's * output fifo into its * output dword buffer. */ -#define XSD2 0x00000008 /* Shift data out on SD2. */ -#define RSD3 0x00001800 /* Shift data in on SD3. */ -#define RSD2 0x00001000 /* Shift data in on SD2. */ -#define LOW_A2 0x00000002 /* Drive last SD low */ - /* for 7 clks, then */ - /* tri-state. */ -#define EOS 0x00000001 /* End of superframe. */ - -/* I2C configuration constants. */ -#define I2C_CLKSEL 0x0400 -/* I2C bit rate = PCIclk/480 = 68.75 KHz. */ - -#define I2C_BITRATE 68.75 -/* I2C bus data bit rate (determined by I2C_CLKSEL) in KHz. */ - -#define I2C_WRTIME 15.0 -/* Worst case time, in msec, for EEPROM internal write op. */ - -/* I2C manifest constants. */ - -/* Max retries to wait for EEPROM write. */ -#define I2C_RETRIES (I2C_WRTIME * I2C_BITRATE / 9.0) -#define I2C_ERR 0x0002 /* I2C control/status */ - /* flag ERROR. */ -#define I2C_BUSY 0x0001 /* I2C control/status */ - /* flag BUSY. */ -#define I2C_ABORT 0x0080 /* I2C status flag ABORT. */ -#define I2C_ATTRSTART 0x3 /* I2C attribute START. */ -#define I2C_ATTRCONT 0x2 /* I2C attribute CONT. */ -#define I2C_ATTRSTOP 0x1 /* I2C attribute STOP. */ -#define I2C_ATTRNOP 0x0 /* I2C attribute NOP. */ - -/* I2C read command | EEPROM address. */ -#define I2CR (devpriv->I2CAdrs | 1) - -/* I2C write command | EEPROM address. */ -#define I2CW (devpriv->I2CAdrs) - -/* Code macros used for constructing I2C command bytes. */ -#define I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) -#define I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) -#define I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) - -/* oldest */ -#define P_DEBICFGq 0x007C /* DEBI configuration. */ -#define P_DEBICMDq 0x0080 /* DEBI command. */ -#define P_DEBIPAGEq 0x0084 /* DEBI page. */ -#define P_DEBIADq 0x0088 /* DEBI target address. */ - -#define DEBI_CFG_TOQ 0x03C00000 /* timeout (15 PCI cycles) */ -#define DEBI_CFG_FASTQ 0x10000000 /* fast mode enable */ -#define DEBI_CFG_16Q 0x00080000 /* 16-bit access enable */ -#define DEBI_CFG_INCQ 0x00040000 /* enable address increment */ -#define DEBI_CFG_TIMEROFFQ 0x00010000 /* disable timer */ -#define DEBI_CMD_RDQ 0x00050000 /* read immediate 2 bytes */ -#define DEBI_CMD_WRQ 0x00040000 /* write immediate 2 bytes */ -#define DEBI_PAGE_DISABLEQ 0x00000000 /* paging disable */ - -/* DEBI command constants. */ -#define DEBI_CMD_SIZE16 (2 << 17) /* Transfer size is */ - /* always 2 bytes. */ -#define DEBI_CMD_READ 0x00010000 /* Read operation. */ -#define DEBI_CMD_WRITE 0x00000000 /* Write operation. */ - -/* Read immediate 2 bytes. */ -#define DEBI_CMD_RDWORD (DEBI_CMD_READ | DEBI_CMD_SIZE16) - -/* Write immediate 2 bytes. */ -#define DEBI_CMD_WRWORD (DEBI_CMD_WRITE | DEBI_CMD_SIZE16) - -/* DEBI configuration constants. */ -#define DEBI_CFG_XIRQ_EN 0x80000000 /* enab external */ - /* interrupt on GPIO3. */ -#define DEBI_CFG_XRESUME 0x40000000 /* Resume block */ - /* transfer when XIRQ */ - /* deasserted. */ -#define DEBI_CFG_FAST 0x10000000 /* Fast mode enable. */ - -/* 4-bit field that specifies DEBI timeout value in PCI clock cycles: */ -#define DEBI_CFG_TOUT_BIT 22 /* Finish DEBI cycle after */ - /* this many clocks. */ - -/* 2-bit field that specifies Endian byte lane steering: */ -#define DEBI_CFG_SWAP_NONE 0x00000000 /* Straight - don't */ - /* swap any bytes */ - /* (Intel). */ -#define DEBI_CFG_SWAP_2 0x00100000 /* 2-byte swap (Motorola). */ -#define DEBI_CFG_SWAP_4 0x00200000 /* 4-byte swap. */ -#define DEBI_CFG_16 0x00080000 /* Slave is able to */ - /* serve 16-bit */ - /* cycles. */ - -#define DEBI_CFG_SLAVE16 0x00080000 /* Slave is able to */ - /* serve 16-bit */ - /* cycles. */ -#define DEBI_CFG_INC 0x00040000 /* enab address */ - /* increment for block */ - /* transfers. */ -#define DEBI_CFG_INTEL 0x00020000 /* Intel style local bus. */ -#define DEBI_CFG_TIMEROFF 0x00010000 /* Disable timer. */ - -#if PLATFORM == INTEL - -#define DEBI_TOUT 7 /* Wait 7 PCI clocks */ - /* (212 ns) before */ - /* polling RDY. */ - -/* Intel byte lane steering (pass through all byte lanes). */ -#define DEBI_SWAP DEBI_CFG_SWAP_NONE - -#elif PLATFORM == MOTOROLA - -#define DEBI_TOUT 15 /* Wait 15 PCI clocks (454 ns) */ - /* maximum before timing out. */ -#define DEBI_SWAP DEBI_CFG_SWAP_2 /* Motorola byte lane steering. */ +#define S626_XSD2 0x00000008 /* Shift data out on SD2. */ +#define S626_RSD3 0x00001800 /* Shift data in on SD3. */ +#define S626_RSD2 0x00001000 /* Shift data in on SD2. */ +#define S626_LOW_A2 0x00000002 /* Drive last SD low for 7 clks, + * then tri-state. */ +#define S626_EOS 0x00000001 /* End of superframe. */ + +/* I2C configuration constants. */ +#define S626_I2C_CLKSEL 0x0400 /* I2C bit rate = + * PCIclk/480 = 68.75 KHz. */ +#define S626_I2C_BITRATE 68.75 /* I2C bus data bit rate + * (determined by + * S626_I2C_CLKSEL) in KHz. */ +#define S626_I2C_WRTIME 15.0 /* Worst case time, in msec, + * for EEPROM internal write + * op. */ + +/* I2C manifest constants. */ + +/* Max retries to wait for EEPROM write. */ +#define S626_I2C_RETRIES (S626_I2C_WRTIME * S626_I2C_BITRATE / 9.0) +#define S626_I2C_ERR 0x0002 /* I2C control/status flag ERROR. */ +#define S626_I2C_BUSY 0x0001 /* I2C control/status flag BUSY. */ +#define S626_I2C_ABORT 0x0080 /* I2C status flag ABORT. */ +#define S626_I2C_ATTRSTART 0x3 /* I2C attribute START. */ +#define S626_I2C_ATTRCONT 0x2 /* I2C attribute CONT. */ +#define S626_I2C_ATTRSTOP 0x1 /* I2C attribute STOP. */ +#define S626_I2C_ATTRNOP 0x0 /* I2C attribute NOP. */ + +/* Code macros used for constructing I2C command bytes. */ +#define S626_I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) +#define S626_I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) +#define S626_I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) + +/* DEBI command constants. */ +#define S626_DEBI_CMD_SIZE16 (2 << 17) /* Transfer size is always + * 2 bytes. */ +#define S626_DEBI_CMD_READ 0x00010000 /* Read operation. */ +#define S626_DEBI_CMD_WRITE 0x00000000 /* Write operation. */ + +/* Read immediate 2 bytes. */ +#define S626_DEBI_CMD_RDWORD (S626_DEBI_CMD_READ | S626_DEBI_CMD_SIZE16) + +/* Write immediate 2 bytes. */ +#define S626_DEBI_CMD_WRWORD (S626_DEBI_CMD_WRITE | S626_DEBI_CMD_SIZE16) + +/* DEBI configuration constants. */ +#define S626_DEBI_CFG_XIRQ_EN 0x80000000 /* Enable external interrupt + * on GPIO3. */ +#define S626_DEBI_CFG_XRESUME 0x40000000 /* Resume block */ + /* Transfer when XIRQ + * deasserted. */ +#define S626_DEBI_CFG_TOQ 0x03C00000 /* Timeout (15 PCI cycles). */ +#define S626_DEBI_CFG_FAST 0x10000000 /* Fast mode enable. */ + +/* 4-bit field that specifies DEBI timeout value in PCI clock cycles: */ +#define S626_DEBI_CFG_TOUT_BIT 22 /* Finish DEBI cycle after this many + * clocks. */ + +/* 2-bit field that specifies Endian byte lane steering: */ +#define S626_DEBI_CFG_SWAP_NONE 0x00000000 /* Straight - don't swap any + * bytes (Intel). */ +#define S626_DEBI_CFG_SWAP_2 0x00100000 /* 2-byte swap (Motorola). */ +#define S626_DEBI_CFG_SWAP_4 0x00200000 /* 4-byte swap. */ +#define S626_DEBI_CFG_SLAVE16 0x00080000 /* Slave is able to serve + * 16-bit cycles. */ +#define S626_DEBI_CFG_INC 0x00040000 /* Enable address increment + * for block transfers. */ +#define S626_DEBI_CFG_INTEL 0x00020000 /* Intel style local bus. */ +#define S626_DEBI_CFG_TIMEROFF 0x00010000 /* Disable timer. */ + +#if S626_PLATFORM == S626_INTEL + +#define S626_DEBI_TOUT 7 /* Wait 7 PCI clocks (212 ns) before + * polling RDY. */ + +/* Intel byte lane steering (pass through all byte lanes). */ +#define S626_DEBI_SWAP S626_DEBI_CFG_SWAP_NONE + +#elif S626_PLATFORM == S626_MOTOROLA + +#define S626_DEBI_TOUT 15 /* Wait 15 PCI clocks (454 ns) maximum + * before timing out. */ + +/* Motorola byte lane steering. */ +#define S626_DEBI_SWAP S626_DEBI_CFG_SWAP_2 #endif -/* DEBI page table constants. */ -#define DEBI_PAGE_DISABLE 0x00000000 /* Paging disable. */ - -/* ******* EXTRA FROM OTHER SANSORAY * .h ******* */ - -/* LoadSrc values: */ -#define LOADSRC_INDX 0 /* Preload core in response to */ - /* Index. */ -#define LOADSRC_OVER 1 /* Preload core in response to */ - /* Overflow. */ -#define LOADSRCB_OVERA 2 /* Preload B core in response */ - /* to A Overflow. */ -#define LOADSRC_NONE 3 /* Never preload core. */ - -/* IntSrc values: */ -#define INTSRC_NONE 0 /* Interrupts disabled. */ -#define INTSRC_OVER 1 /* Interrupt on Overflow. */ -#define INTSRC_INDX 2 /* Interrupt on Index. */ -#define INTSRC_BOTH 3 /* Interrupt on Index or Overflow. */ - -/* LatchSrc values: */ -#define LATCHSRC_AB_READ 0 /* Latch on read. */ -#define LATCHSRC_A_INDXA 1 /* Latch A on A Index. */ -#define LATCHSRC_B_INDXB 2 /* Latch B on B Index. */ -#define LATCHSRC_B_OVERA 3 /* Latch B on A Overflow. */ - -/* IndxSrc values: */ -#define INDXSRC_HARD 0 /* Hardware or software index. */ -#define INDXSRC_SOFT 1 /* Software index only. */ - -/* IndxPol values: */ -#define INDXPOL_POS 0 /* Index input is active high. */ -#define INDXPOL_NEG 1 /* Index input is active low. */ - -/* ClkSrc values: */ -#define CLKSRC_COUNTER 0 /* Counter mode. */ -#define CLKSRC_TIMER 2 /* Timer mode. */ -#define CLKSRC_EXTENDER 3 /* Extender mode. */ - -/* ClkPol values: */ -#define CLKPOL_POS 0 /* Counter/Extender clock is */ - /* active high. */ -#define CLKPOL_NEG 1 /* Counter/Extender clock is */ - /* active low. */ -#define CNTDIR_UP 0 /* Timer counts up. */ -#define CNTDIR_DOWN 1 /* Timer counts down. */ - -/* ClkEnab values: */ -#define CLKENAB_ALWAYS 0 /* Clock always enabled. */ -#define CLKENAB_INDEX 1 /* Clock is enabled by index. */ - -/* ClkMult values: */ -#define CLKMULT_4X 0 /* 4x clock multiplier. */ -#define CLKMULT_2X 1 /* 2x clock multiplier. */ -#define CLKMULT_1X 2 /* 1x clock multiplier. */ - -/* Bit Field positions in COUNTER_SETUP structure: */ -#define BF_LOADSRC 9 /* Preload trigger. */ -#define BF_INDXSRC 7 /* Index source. */ -#define BF_INDXPOL 6 /* Index polarity. */ -#define BF_CLKSRC 4 /* Clock source. */ -#define BF_CLKPOL 3 /* Clock polarity/count direction. */ -#define BF_CLKMULT 1 /* Clock multiplier. */ -#define BF_CLKENAB 0 /* Clock enable. */ - -/* Enumerated counter operating modes specified by ClkSrc bit field in */ -/* a COUNTER_SETUP. */ - -#define CLKSRC_COUNTER 0 /* Counter: ENC_C clock, ENC_D */ - /* direction. */ -#define CLKSRC_TIMER 2 /* Timer: SYS_C clock, */ - /* direction specified by */ - /* ClkPol. */ -#define CLKSRC_EXTENDER 3 /* Extender: OVR_A clock, */ - /* ENC_D direction. */ - -/* Enumerated counter clock multipliers. */ - -#define MULT_X0 0x0003 /* Supports no multipliers; */ - /* fixed physical multiplier = */ - /* 3. */ -#define MULT_X1 0x0002 /* Supports multiplier x1; */ - /* fixed physical multiplier = */ - /* 2. */ -#define MULT_X2 0x0001 /* Supports multipliers x1, */ - /* x2; physical multipliers = */ - /* 1 or 2. */ -#define MULT_X4 0x0000 /* Supports multipliers x1, */ - /* x2, x4; physical */ - /* multipliers = 0, 1 or 2. */ - -/* Sanity-check limits for parameters. */ - -#define NUM_COUNTERS 6 /* Maximum valid counter */ - /* logical channel number. */ -#define NUM_INTSOURCES 4 -#define NUM_LATCHSOURCES 4 -#define NUM_CLKMULTS 4 -#define NUM_CLKSOURCES 4 -#define NUM_CLKPOLS 2 -#define NUM_INDEXPOLS 2 -#define NUM_INDEXSOURCES 2 -#define NUM_LOADTRIGS 4 - -/* Bit field positions in CRA and CRB counter control registers. */ - -/* Bit field positions in CRA: */ -#define CRABIT_INDXSRC_B 14 /* B index source. */ -#define CRABIT_CLKSRC_B 12 /* B clock source. */ -#define CRABIT_INDXPOL_A 11 /* A index polarity. */ -#define CRABIT_LOADSRC_A 9 /* A preload trigger. */ -#define CRABIT_CLKMULT_A 7 /* A clock multiplier. */ -#define CRABIT_INTSRC_A 5 /* A interrupt source. */ -#define CRABIT_CLKPOL_A 4 /* A clock polarity. */ -#define CRABIT_INDXSRC_A 2 /* A index source. */ -#define CRABIT_CLKSRC_A 0 /* A clock source. */ - -/* Bit field positions in CRB: */ -#define CRBBIT_INTRESETCMD 15 /* Interrupt reset command. */ -#define CRBBIT_INTRESET_B 14 /* B interrupt reset enable. */ -#define CRBBIT_INTRESET_A 13 /* A interrupt reset enable. */ -#define CRBBIT_CLKENAB_A 12 /* A clock enable. */ -#define CRBBIT_INTSRC_B 10 /* B interrupt source. */ -#define CRBBIT_LATCHSRC 8 /* A/B latch source. */ -#define CRBBIT_LOADSRC_B 6 /* B preload trigger. */ -#define CRBBIT_CLKMULT_B 3 /* B clock multiplier. */ -#define CRBBIT_CLKENAB_B 2 /* B clock enable. */ -#define CRBBIT_INDXPOL_B 1 /* B index polarity. */ -#define CRBBIT_CLKPOL_B 0 /* B clock polarity. */ - -/* Bit field masks for CRA and CRB. */ - -#define CRAMSK_INDXSRC_B (3 << CRABIT_INDXSRC_B) -#define CRAMSK_CLKSRC_B (3 << CRABIT_CLKSRC_B) -#define CRAMSK_INDXPOL_A (1 << CRABIT_INDXPOL_A) -#define CRAMSK_LOADSRC_A (3 << CRABIT_LOADSRC_A) -#define CRAMSK_CLKMULT_A (3 << CRABIT_CLKMULT_A) -#define CRAMSK_INTSRC_A (3 << CRABIT_INTSRC_A) -#define CRAMSK_CLKPOL_A (3 << CRABIT_CLKPOL_A) -#define CRAMSK_INDXSRC_A (3 << CRABIT_INDXSRC_A) -#define CRAMSK_CLKSRC_A (3 << CRABIT_CLKSRC_A) - -#define CRBMSK_INTRESETCMD (1 << CRBBIT_INTRESETCMD) -#define CRBMSK_INTRESET_B (1 << CRBBIT_INTRESET_B) -#define CRBMSK_INTRESET_A (1 << CRBBIT_INTRESET_A) -#define CRBMSK_CLKENAB_A (1 << CRBBIT_CLKENAB_A) -#define CRBMSK_INTSRC_B (3 << CRBBIT_INTSRC_B) -#define CRBMSK_LATCHSRC (3 << CRBBIT_LATCHSRC) -#define CRBMSK_LOADSRC_B (3 << CRBBIT_LOADSRC_B) -#define CRBMSK_CLKMULT_B (3 << CRBBIT_CLKMULT_B) -#define CRBMSK_CLKENAB_B (1 << CRBBIT_CLKENAB_B) -#define CRBMSK_INDXPOL_B (1 << CRBBIT_INDXPOL_B) -#define CRBMSK_CLKPOL_B (1 << CRBBIT_CLKPOL_B) - -#define CRBMSK_INTCTRL (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A | CRBMSK_INTRESET_B) /* Interrupt reset control bits. */ - -/* Bit field positions for standardized SETUP structure. */ - -#define STDBIT_INTSRC 13 -#define STDBIT_LATCHSRC 11 -#define STDBIT_LOADSRC 9 -#define STDBIT_INDXSRC 7 -#define STDBIT_INDXPOL 6 -#define STDBIT_CLKSRC 4 -#define STDBIT_CLKPOL 3 -#define STDBIT_CLKMULT 1 -#define STDBIT_CLKENAB 0 - -/* Bit field masks for standardized SETUP structure. */ - -#define STDMSK_INTSRC (3 << STDBIT_INTSRC) -#define STDMSK_LATCHSRC (3 << STDBIT_LATCHSRC) -#define STDMSK_LOADSRC (3 << STDBIT_LOADSRC) -#define STDMSK_INDXSRC (1 << STDBIT_INDXSRC) -#define STDMSK_INDXPOL (1 << STDBIT_INDXPOL) -#define STDMSK_CLKSRC (3 << STDBIT_CLKSRC) -#define STDMSK_CLKPOL (1 << STDBIT_CLKPOL) -#define STDMSK_CLKMULT (3 << STDBIT_CLKMULT) -#define STDMSK_CLKENAB (1 << STDBIT_CLKENAB) - -struct bufferDMA { - dma_addr_t PhysicalBase; - void *LogicalBase; - uint32_t DMAHandle; -}; +/* DEBI page table constants. */ +#define S626_DEBI_PAGE_DISABLE 0x00000000 /* Paging disable. */ + +/* ******* EXTRA FROM OTHER SENSORAY * .h ******* */ + +/* LoadSrc values: */ +#define S626_LOADSRC_INDX 0 /* Preload core in response to Index. */ +#define S626_LOADSRC_OVER 1 /* Preload core in response to + * Overflow. */ +#define S626_LOADSRCB_OVERA 2 /* Preload B core in response to + * A Overflow. */ +#define S626_LOADSRC_NONE 3 /* Never preload core. */ + +/* IntSrc values: */ +#define S626_INTSRC_NONE 0 /* Interrupts disabled. */ +#define S626_INTSRC_OVER 1 /* Interrupt on Overflow. */ +#define S626_INTSRC_INDX 2 /* Interrupt on Index. */ +#define S626_INTSRC_BOTH 3 /* Interrupt on Index or Overflow. */ + +/* LatchSrc values: */ +#define S626_LATCHSRC_AB_READ 0 /* Latch on read. */ +#define S626_LATCHSRC_A_INDXA 1 /* Latch A on A Index. */ +#define S626_LATCHSRC_B_INDXB 2 /* Latch B on B Index. */ +#define S626_LATCHSRC_B_OVERA 3 /* Latch B on A Overflow. */ + +/* IndxSrc values: */ +#define S626_INDXSRC_HARD 0 /* Hardware or software index. */ +#define S626_INDXSRC_SOFT 1 /* Software index only. */ + +/* IndxPol values: */ +#define S626_INDXPOL_POS 0 /* Index input is active high. */ +#define S626_INDXPOL_NEG 1 /* Index input is active low. */ + +/* ClkSrc values: */ +#define S626_CLKSRC_COUNTER 0 /* Counter mode. */ +#define S626_CLKSRC_TIMER 2 /* Timer mode. */ +#define S626_CLKSRC_EXTENDER 3 /* Extender mode. */ + +/* ClkPol values: */ +#define S626_CLKPOL_POS 0 /* Counter/Extender clock is + * active high. */ +#define S626_CLKPOL_NEG 1 /* Counter/Extender clock is + * active low. */ +#define S626_CNTDIR_UP 0 /* Timer counts up. */ +#define S626_CNTDIR_DOWN 1 /* Timer counts down. */ + +/* ClkEnab values: */ +#define S626_CLKENAB_ALWAYS 0 /* Clock always enabled. */ +#define S626_CLKENAB_INDEX 1 /* Clock is enabled by index. */ + +/* ClkMult values: */ +#define S626_CLKMULT_4X 0 /* 4x clock multiplier. */ +#define S626_CLKMULT_2X 1 /* 2x clock multiplier. */ +#define S626_CLKMULT_1X 2 /* 1x clock multiplier. */ + +/* Bit Field positions in COUNTER_SETUP structure: */ +#define S626_BF_LOADSRC 9 /* Preload trigger. */ +#define S626_BF_INDXSRC 7 /* Index source. */ +#define S626_BF_INDXPOL 6 /* Index polarity. */ +#define S626_BF_CLKSRC 4 /* Clock source. */ +#define S626_BF_CLKPOL 3 /* Clock polarity/count direction. */ +#define S626_BF_CLKMULT 1 /* Clock multiplier. */ +#define S626_BF_CLKENAB 0 /* Clock enable. */ + +/* Enumerated counter clock multipliers. */ + +#define S626_MULT_X0 0x0003 /* Supports no multipliers; + * fixed physical multiplier = 3. */ +#define S626_MULT_X1 0x0002 /* Supports multiplier x1; + * fixed physical multiplier = 2. */ +#define S626_MULT_X2 0x0001 /* Supports multipliers x1, x2; + * physical multipliers = 1 or 2. */ +#define S626_MULT_X4 0x0000 /* Supports multipliers x1, x2, x4; + * physical multipliers = 0, 1 or 2. */ + +/* Sanity-check limits for parameters. */ + +#define S626_NUM_COUNTERS 6 /* Maximum valid counter + * logical channel number. */ +#define S626_NUM_INTSOURCES 4 +#define S626_NUM_LATCHSOURCES 4 +#define S626_NUM_CLKMULTS 4 +#define S626_NUM_CLKSOURCES 4 +#define S626_NUM_CLKPOLS 2 +#define S626_NUM_INDEXPOLS 2 +#define S626_NUM_INDEXSOURCES 2 +#define S626_NUM_LOADTRIGS 4 + +/* Bit field positions in CRA and CRB counter control registers. */ + +/* Bit field positions in CRA: */ +#define S626_CRABIT_INDXSRC_B 14 /* B index source. */ +#define S626_CRABIT_CLKSRC_B 12 /* B clock source. */ +#define S626_CRABIT_INDXPOL_A 11 /* A index polarity. */ +#define S626_CRABIT_LOADSRC_A 9 /* A preload trigger. */ +#define S626_CRABIT_CLKMULT_A 7 /* A clock multiplier. */ +#define S626_CRABIT_INTSRC_A 5 /* A interrupt source. */ +#define S626_CRABIT_CLKPOL_A 4 /* A clock polarity. */ +#define S626_CRABIT_INDXSRC_A 2 /* A index source. */ +#define S626_CRABIT_CLKSRC_A 0 /* A clock source. */ + +/* Bit field positions in CRB: */ +#define S626_CRBBIT_INTRESETCMD 15 /* Interrupt reset command. */ +#define S626_CRBBIT_INTRESET_B 14 /* B interrupt reset enable. */ +#define S626_CRBBIT_INTRESET_A 13 /* A interrupt reset enable. */ +#define S626_CRBBIT_CLKENAB_A 12 /* A clock enable. */ +#define S626_CRBBIT_INTSRC_B 10 /* B interrupt source. */ +#define S626_CRBBIT_LATCHSRC 8 /* A/B latch source. */ +#define S626_CRBBIT_LOADSRC_B 6 /* B preload trigger. */ +#define S626_CRBBIT_CLKMULT_B 3 /* B clock multiplier. */ +#define S626_CRBBIT_CLKENAB_B 2 /* B clock enable. */ +#define S626_CRBBIT_INDXPOL_B 1 /* B index polarity. */ +#define S626_CRBBIT_CLKPOL_B 0 /* B clock polarity. */ + +/* Bit field masks for CRA and CRB. */ + +#define S626_CRAMSK_INDXSRC_B (3 << S626_CRABIT_INDXSRC_B) +#define S626_CRAMSK_CLKSRC_B (3 << S626_CRABIT_CLKSRC_B) +#define S626_CRAMSK_INDXPOL_A (1 << S626_CRABIT_INDXPOL_A) +#define S626_CRAMSK_LOADSRC_A (3 << S626_CRABIT_LOADSRC_A) +#define S626_CRAMSK_CLKMULT_A (3 << S626_CRABIT_CLKMULT_A) +#define S626_CRAMSK_INTSRC_A (3 << S626_CRABIT_INTSRC_A) +#define S626_CRAMSK_CLKPOL_A (3 << S626_CRABIT_CLKPOL_A) +#define S626_CRAMSK_INDXSRC_A (3 << S626_CRABIT_INDXSRC_A) +#define S626_CRAMSK_CLKSRC_A (3 << S626_CRABIT_CLKSRC_A) + +#define S626_CRBMSK_INTRESETCMD (1 << S626_CRBBIT_INTRESETCMD) +#define S626_CRBMSK_INTRESET_B (1 << S626_CRBBIT_INTRESET_B) +#define S626_CRBMSK_INTRESET_A (1 << S626_CRBBIT_INTRESET_A) +#define S626_CRBMSK_CLKENAB_A (1 << S626_CRBBIT_CLKENAB_A) +#define S626_CRBMSK_INTSRC_B (3 << S626_CRBBIT_INTSRC_B) +#define S626_CRBMSK_LATCHSRC (3 << S626_CRBBIT_LATCHSRC) +#define S626_CRBMSK_LOADSRC_B (3 << S626_CRBBIT_LOADSRC_B) +#define S626_CRBMSK_CLKMULT_B (3 << S626_CRBBIT_CLKMULT_B) +#define S626_CRBMSK_CLKENAB_B (1 << S626_CRBBIT_CLKENAB_B) +#define S626_CRBMSK_INDXPOL_B (1 << S626_CRBBIT_INDXPOL_B) +#define S626_CRBMSK_CLKPOL_B (1 << S626_CRBBIT_CLKPOL_B) + +/* Interrupt reset control bits. */ +#define S626_CRBMSK_INTCTRL (S626_CRBMSK_INTRESETCMD | \ + S626_CRBMSK_INTRESET_A | \ + S626_CRBMSK_INTRESET_B) + +/* Bit field positions for standardized SETUP structure. */ + +#define S626_STDBIT_INTSRC 13 +#define S626_STDBIT_LATCHSRC 11 +#define S626_STDBIT_LOADSRC 9 +#define S626_STDBIT_INDXSRC 7 +#define S626_STDBIT_INDXPOL 6 +#define S626_STDBIT_CLKSRC 4 +#define S626_STDBIT_CLKPOL 3 +#define S626_STDBIT_CLKMULT 1 +#define S626_STDBIT_CLKENAB 0 + +/* Bit field masks for standardized SETUP structure. */ + +#define S626_STDMSK_INTSRC (3 << S626_STDBIT_INTSRC) +#define S626_STDMSK_LATCHSRC (3 << S626_STDBIT_LATCHSRC) +#define S626_STDMSK_LOADSRC (3 << S626_STDBIT_LOADSRC) +#define S626_STDMSK_INDXSRC (1 << S626_STDBIT_INDXSRC) +#define S626_STDMSK_INDXPOL (1 << S626_STDBIT_INDXPOL) +#define S626_STDMSK_CLKSRC (3 << S626_STDBIT_CLKSRC) +#define S626_STDMSK_CLKPOL (1 << S626_STDBIT_CLKPOL) +#define S626_STDMSK_CLKMULT (3 << S626_STDBIT_CLKMULT) +#define S626_STDMSK_CLKENAB (1 << S626_STDBIT_CLKENAB) + +#endif diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index 9e964950a560..daee2f42bde0 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -332,30 +332,44 @@ static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* DIO devices are slightly special. Although it is possible to +/* + * DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ + * This allows packed reading/writing of the DIO channels. The + * comedi core can convert between insn_bits and insn_read/write. + */ static int skel_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + /* + * The insn data is a mask in data[0] and the new data + * in data[1], each channel cooresponding to a bit. + * + * The core provided comedi_dio_update_state() function can + * be used to handle the internal state update to DIO subdevices + * with <= 32 channels. This function will return '0' if the + * state does not change or the mask of the channels that need + * to be updated. + */ + if (comedi_dio_update_state(s, data)) { /* Write out the new digital output lines */ - /* outw(s->state,dev->iobase + SKEL_DIO); */ + /* outw(s->state, dev->iobase + SKEL_DIO); */ } - /* on return, data[1] contains the value of the digital - * input and output lines. */ - /* data[1]=inw(dev->iobase + SKEL_DIO); */ - /* or we could just return the software copy of the output values if - * it was a purely digital output subdevice */ - /* data[1]=s->state; */ + /* + * On return, data[1] contains the value of the digital + * input and output lines. + */ + /* data[1] = inw(dev->iobase + SKEL_DIO); */ + + /* + * Or we could just return the software copy of the output + * values if it was a purely digital output subdevice. + */ + /* data[1] = s->state; */ return insn->n; } diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index 11758a515c1b..df22a78d2b7e 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -46,51 +46,43 @@ Status: unknown #define PCMR 0xa3 /* Port C Mode Register */ #define PCDR 0xa7 /* Port C Data Register */ -/* ------------------------------------------------------------------------- */ -/* The insn_bits interface allows packed reading/writing of DIO channels. */ -/* The comedi core can convert between insn_bits and insn_read/write, so you */ -/* are able to use these instructions as well. */ -/* ------------------------------------------------------------------------- */ - static int dnp_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* The insn data is a mask in data[0] and the new data in data[1], */ - /* each channel cooresponding to a bit. */ - - /* Ports A and B are straight forward: each bit corresponds to an */ - /* output pin with the same order. Port C is different: bits 0...3 */ - /* correspond to bits 4...7 of the output register (PCDR). */ + unsigned int mask; + unsigned int val; - if (data[0]) { + /* + * Ports A and B are straight forward: each bit corresponds to an + * output pin with the same order. Port C is different: bits 0...3 + * correspond to bits 4...7 of the output register (PCDR). + */ + mask = comedi_dio_update_state(s, data); + if (mask) { outb(PADR, CSCIR); - outb((inb(CSCDR) - & ~(u8) (data[0] & 0x0000FF)) - | (u8) (data[1] & 0x0000FF), CSCDR); + outb(s->state & 0xff, CSCDR); outb(PBDR, CSCIR); - outb((inb(CSCDR) - & ~(u8) ((data[0] & 0x00FF00) >> 8)) - | (u8) ((data[1] & 0x00FF00) >> 8), CSCDR); + outb((s->state >> 8) & 0xff, CSCDR); outb(PCDR, CSCIR); - outb((inb(CSCDR) - & ~(u8) ((data[0] & 0x0F0000) >> 12)) - | (u8) ((data[1] & 0x0F0000) >> 12), CSCDR); + val = inb(CSCDR) & 0x0f; + outb(((s->state >> 12) & 0xf0) | val, CSCDR); } - /* on return, data[1] contains the value of the digital input lines. */ outb(PADR, CSCIR); - data[0] = inb(CSCDR); + val = inb(CSCDR); outb(PBDR, CSCIR); - data[0] += inb(CSCDR) << 8; + val |= (inb(CSCDR) << 8); outb(PCDR, CSCIR); - data[0] += ((inb(CSCDR) & 0xF0) << 12); + val |= ((inb(CSCDR) & 0xf0) << 12); - return insn->n; + data[1] = val; + return insn->n; } static int dnp_dio_insn_config(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 701ad1a69394..da1d501d9e4e 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -122,7 +122,7 @@ sampling rate. If you sample two channels you get 4kHz and so on. #define PWM_DEFAULT_PERIOD ((long)(1E9/100)) /* Size of one A/D value */ -#define SIZEADIN ((sizeof(int16_t))) +#define SIZEADIN ((sizeof(uint16_t))) /* * Size of the input-buffer IN BYTES @@ -134,7 +134,7 @@ sampling rate. If you sample two channels you get 4kHz and so on. #define SIZEINSNBUF 16 /* size of one value for the D/A converter: channel and value */ -#define SIZEDAOUT ((sizeof(int8_t)+sizeof(int16_t))) +#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(uint16_t))) /* * Size of the output-buffer in bytes @@ -195,15 +195,15 @@ struct usbdux_private { /* PWM period */ unsigned int pwm_period; /* PWM internal delay for the GPIF in the FX2 */ - int8_t pwm_delay; + uint8_t pwm_delay; /* size of the PWM buffer which holds the bit pattern */ int pwm_buf_sz; /* input buffer for the ISO-transfer */ - int16_t *in_buf; + uint16_t *in_buf; /* input buffer for single insn */ - int16_t *insn_buf; + uint16_t *insn_buf; - int8_t ao_chanlist[USBDUX_NUM_AO_CHAN]; + uint8_t ao_chanlist[USBDUX_NUM_AO_CHAN]; unsigned int ao_readback[USBDUX_NUM_AO_CHAN]; unsigned int high_speed:1; @@ -225,7 +225,7 @@ struct usbdux_private { /* interval in frames/uframes */ unsigned int ai_interval; /* commands */ - int8_t *dux_commands; + uint8_t *dux_commands; struct semaphore sem; }; @@ -367,7 +367,7 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb) n = s->async->cmd.chanlist_len; for (i = 0; i < n; i++) { unsigned int range = CR_RANGE(s->async->cmd.chanlist[i]); - int16_t val = le16_to_cpu(devpriv->in_buf[i]); + uint16_t val = le16_to_cpu(devpriv->in_buf[i]); /* bipolar data is two's-complement */ if (comedi_range_is_bipolar(s, range)) @@ -415,7 +415,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) struct comedi_device *dev = urb->context; struct comedi_subdevice *s = dev->write_subdev; struct usbdux_private *devpriv = dev->private; - int8_t *datap; + uint8_t *datap; int len; int ret; int i; @@ -483,7 +483,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb) *datap++ = len; for (i = 0; i < s->async->cmd.chanlist_len; i++) { unsigned int chan = devpriv->ao_chanlist[i]; - short val; + unsigned short val; ret = comedi_buf_get(s->async, &val); if (ret < 0) { @@ -649,14 +649,15 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, * creates the ADC command for the MAX1271 * range is the range value from comedi */ -static int8_t create_adc_command(unsigned int chan, int range) +static uint8_t create_adc_command(unsigned int chan, unsigned int range) { - int8_t p = (range <= 1); - int8_t r = ((range % 2) == 0); + uint8_t p = (range <= 1); + uint8_t r = ((range % 2) == 0); + return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3); } -static int send_dux_commands(struct comedi_device *dev, int cmd_type) +static int send_dux_commands(struct comedi_device *dev, unsigned int cmd_type) { struct usb_device *usb = comedi_to_usb_dev(dev); struct usbdux_private *devpriv = dev->private; @@ -669,7 +670,7 @@ static int send_dux_commands(struct comedi_device *dev, int cmd_type) &nsent, BULK_TIMEOUT); } -static int receive_dux_commands(struct comedi_device *dev, int command) +static int receive_dux_commands(struct comedi_device *dev, unsigned int command) { struct usb_device *usb = comedi_to_usb_dev(dev); struct usbdux_private *devpriv = dev->private; @@ -879,7 +880,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev, struct usbdux_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int val = devpriv->ao_readback[chan]; - int16_t *p = (int16_t *)&devpriv->dux_commands[2]; + uint16_t *p = (uint16_t *)&devpriv->dux_commands[2]; int ret = -EBUSY; int i; @@ -1133,15 +1134,13 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev, { struct usbdux_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; int ret; down(&devpriv->sem); - s->state &= ~mask; - s->state |= (bits & mask); + comedi_dio_update_state(s, data); + /* Always update the hardware. See the (*insn_config). */ devpriv->dux_commands[1] = s->io_bits; devpriv->dux_commands[2] = s->state; @@ -1200,7 +1199,7 @@ static int usbdux_counter_write(struct comedi_device *dev, { struct usbdux_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - int16_t *p = (int16_t *)&devpriv->dux_commands[2]; + uint16_t *p = (uint16_t *)&devpriv->dux_commands[2]; int ret = 0; int i; diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index c47f4087568f..a5363ded3668 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -78,7 +78,7 @@ #define USBDUXSIGMA_NUM_AO_CHAN 4 /* Size of one A/D value */ -#define SIZEADIN ((sizeof(int32_t))) +#define SIZEADIN ((sizeof(uint32_t))) /* * Size of the async input-buffer IN BYTES, the DIO state is transmitted @@ -93,7 +93,7 @@ #define NUMOUTCHANNELS 8 /* size of one value for the D/A converter: channel and value */ -#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(int16_t))) +#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(uint16_t))) /* * Size of the output-buffer in bytes @@ -157,11 +157,11 @@ struct usbduxsigma_private { /* size of the PWM buffer which holds the bit pattern */ int pwm_buf_sz; /* input buffer for the ISO-transfer */ - int32_t *in_buf; + uint32_t *in_buf; /* input buffer for single insn */ - int8_t *insn_buf; + uint8_t *insn_buf; - int8_t ao_chanlist[USBDUXSIGMA_NUM_AO_CHAN]; + uint8_t ao_chanlist[USBDUXSIGMA_NUM_AO_CHAN]; unsigned int ao_readback[USBDUXSIGMA_NUM_AO_CHAN]; unsigned high_speed:1; @@ -224,7 +224,7 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb) struct usbduxsigma_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; unsigned int dio_state; - int32_t val; + uint32_t val; int ret; int i; @@ -421,7 +421,7 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb) *datap++ = len; for (i = 0; i < len; i++) { unsigned int chan = devpriv->ao_chanlist[i]; - short val; + unsigned short val; ret = comedi_buf_get(s->async, &val); if (ret < 0) { @@ -784,7 +784,7 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, } for (i = 0; i < insn->n; i++) { - int32_t val; + uint32_t val; ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); if (ret < 0) { @@ -793,7 +793,7 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, } /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(*((int32_t *)((devpriv->insn_buf) + 1))); + val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf) + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ @@ -1059,15 +1059,13 @@ static int usbduxsigma_dio_insn_bits(struct comedi_device *dev, unsigned int *data) { struct usbduxsigma_private *devpriv = dev->private; - unsigned int mask = data[0]; - unsigned int bits = data[1]; int ret; down(&devpriv->sem); - s->state &= ~mask; - s->state |= (bits & mask); + comedi_dio_update_state(s, data); + /* Always update the hardware. See the (*insn_config). */ devpriv->dux_commands[1] = s->io_bits & 0xff; devpriv->dux_commands[4] = s->state & 0xff; devpriv->dux_commands[2] = (s->io_bits >> 8) & 0xff; @@ -1360,7 +1358,7 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) return ret; /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(*((int32_t *)((devpriv->insn_buf)+1))); + val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf)+1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 06efa16b9af2..933b01a0f03d 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -462,9 +462,10 @@ static int vmk80xx_do_insn_bits(struct comedi_device *dev, unsigned int *data) { struct vmk80xx_private *devpriv = dev->private; - unsigned char *rx_buf, *tx_buf; + unsigned char *rx_buf = devpriv->usb_rx_buf; + unsigned char *tx_buf = devpriv->usb_tx_buf; int reg, cmd; - int retval; + int ret; if (devpriv->model == VMK8061_MODEL) { reg = VMK8061_DO_REG; @@ -476,37 +477,27 @@ static int vmk80xx_do_insn_bits(struct comedi_device *dev, down(&devpriv->limit_sem); - rx_buf = devpriv->usb_rx_buf; - tx_buf = devpriv->usb_tx_buf; - - if (data[0]) { - tx_buf[reg] &= ~data[0]; - tx_buf[reg] |= (data[0] & data[1]); - - retval = vmk80xx_write_packet(dev, cmd); - - if (retval) + if (comedi_dio_update_state(s, data)) { + tx_buf[reg] = s->state; + ret = vmk80xx_write_packet(dev, cmd); + if (ret) goto out; } if (devpriv->model == VMK8061_MODEL) { tx_buf[0] = VMK8061_CMD_RD_DO; - - retval = vmk80xx_read_packet(dev); - - if (!retval) { - data[1] = rx_buf[reg]; - retval = 2; - } + ret = vmk80xx_read_packet(dev); + if (ret) + goto out; + data[1] = rx_buf[reg]; } else { - data[1] = tx_buf[reg]; - retval = 2; + data[1] = s->state; } out: up(&devpriv->limit_sem); - return retval; + return ret ? ret : insn->n; } static int vmk80xx_cnt_insn_read(struct comedi_device *dev, diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c index 5845e899ee80..043bd49843ff 100644 --- a/drivers/staging/crystalhd/crystalhd_hw.c +++ b/drivers/staging/crystalhd/crystalhd_hw.c @@ -1517,7 +1517,7 @@ static void crystalhd_rx_isr(struct crystalhd_hw *hw, uint32_t intr_sts) uint32_t i, list_avail = 0; enum BC_STATUS comp_sts = BC_STS_NO_DATA; uint32_t y_err_sts, uv_err_sts, y_dn_sz = 0, uv_dn_sz = 0; - bool ret = 0; + bool ret = false; if (!hw) { BCMLOG_ERR("Invalid Arguments\n"); @@ -1852,7 +1852,7 @@ bool crystalhd_hw_interrupt(struct crystalhd_adp *adp, struct crystalhd_hw *hw) { uint32_t intr_sts = 0; uint32_t deco_intr = 0; - bool rc = 0; + bool rc = false; if (!adp || !hw->dev_started) return rc; @@ -1865,7 +1865,7 @@ bool crystalhd_hw_interrupt(struct crystalhd_adp *adp, struct crystalhd_hw *hw) if (intr_sts) { /* let system know we processed interrupt..*/ - rc = 1; + rc = true; hw->stats.dev_interrupts++; } @@ -1886,7 +1886,7 @@ bool crystalhd_hw_interrupt(struct crystalhd_adp *adp, struct crystalhd_hw *hw) /* FIXME: jarod: No udelay? might this be the real reason mini pci-e cards were stalling out? */ bc_dec_reg_wr(adp, Stream2Host_Intr_Sts, 0); - rc = 1; + rc = true; } /* Rx interrupts */ diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c index b17fbf8181cf..190b9b924368 100644 --- a/drivers/staging/crystalhd/crystalhd_lnx.c +++ b/drivers/staging/crystalhd/crystalhd_lnx.c @@ -75,8 +75,9 @@ static int chd_dec_disable_int(struct crystalhd_adp *adp) return 0; } -struct crystalhd_ioctl_data *chd_dec_alloc_iodata(struct crystalhd_adp *adp, - bool isr) +static struct +crystalhd_ioctl_data *chd_dec_alloc_iodata(struct crystalhd_adp *adp, + bool isr) { unsigned long flags = 0; struct crystalhd_ioctl_data *temp; @@ -96,8 +97,8 @@ struct crystalhd_ioctl_data *chd_dec_alloc_iodata(struct crystalhd_adp *adp, return temp; } -void chd_dec_free_iodata(struct crystalhd_adp *adp, - struct crystalhd_ioctl_data *iodata, bool isr) +static void chd_dec_free_iodata(struct crystalhd_adp *adp, + struct crystalhd_ioctl_data *iodata, bool isr) { unsigned long flags = 0; @@ -156,7 +157,7 @@ static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, if (rc) { BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n", io->add_cdata_sz, (unsigned int)ua_off); - kfree(io->add_cdata); + vfree(io->add_cdata); io->add_cdata = NULL; return -ENODATA; } @@ -627,7 +628,7 @@ err: } #ifdef CONFIG_PM -int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct crystalhd_adp *adp; struct crystalhd_ioctl_data *temp; @@ -661,7 +662,7 @@ int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -int chd_dec_pci_resume(struct pci_dev *pdev) +static int chd_dec_pci_resume(struct pci_dev *pdev) { struct crystalhd_adp *adp; enum BC_STATUS sts = BC_STS_SUCCESS; diff --git a/drivers/staging/cxt1e1/comet.c b/drivers/staging/cxt1e1/comet.c index d71aea541811..46a0d92173e0 100644 --- a/drivers/staging/cxt1e1/comet.c +++ b/drivers/staging/cxt1e1/comet.c @@ -145,10 +145,8 @@ void init_comet(void *ci, comet_t *comet, u_int32_t port_mode, int clockmaster, /* Enable 8 out of 10 validation */ /* t1RBOC enable(BOC:BitOriented Code) */ pci_write_32((u_int32_t *) &comet->t1_rboc_ena, 0x00); - if (isT1mode) - { - - /* IBCD cfg: aka Inband Code Detection ** loopback code length set to */ + if (isT1mode) { + /* IBCD cfg: aka Inband Code Detection ** loopback code length set to */ /* 6 bit down, 5 bit up (assert) */ pci_write_32((u_int32_t *) &comet->ibcd_cfg, 0x04); /* line loopback activate pattern */ @@ -353,7 +351,7 @@ void init_comet(void *ci, comet_t *comet, u_int32_t port_mode, int clockmaster, /* RLPS Configuration Status */ pci_write_32((u_int32_t *) &comet->rlps_cfgsts, 0x11); if (isT1mode) - /* ? */ + /* ? */ pci_write_32((u_int32_t *) &comet->rlps_alos_thresh, 0x55); else /* ? */ @@ -452,7 +450,7 @@ WrtRcvEqualizerTbl(ci_t *ci, comet_t *comet, u_int32_t *table) volatile u_int32_t value; for (ramaddr = 0; ramaddr < 256; ramaddr++) { - /*** the following lines are per Errata 7, 2.5 ***/ + /*** the following lines are per Errata 7, 2.5 ***/ { /* Set up for a read operation */ pci_write_32((u_int32_t *) &comet->rlps_eq_rwsel, 0x80); diff --git a/drivers/staging/cxt1e1/comet.h b/drivers/staging/cxt1e1/comet.h index e06da4a6f6f6..03b9bb77a809 100644 --- a/drivers/staging/cxt1e1/comet.h +++ b/drivers/staging/cxt1e1/comet.h @@ -338,7 +338,7 @@ typedef struct s_comet_reg comet_t; #ifdef __KERNEL__ extern void -init_comet (void *, comet_t *, u_int32_t, int, u_int8_t); +init_comet(void *, comet_t *, u_int32_t, int, u_int8_t); #endif #endif /* _INC_COMET_H_ */ diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c index 53e923701ae6..02b4f8f1aca5 100644 --- a/drivers/staging/cxt1e1/hwprobe.c +++ b/drivers/staging/cxt1e1/hwprobe.c @@ -157,7 +157,7 @@ prep_hdw_info (void) hi->pci_slot = 0xff; hi->pci_pin[0] = 0; hi->pci_pin[1] = 0; - hi->ndev = 0; + hi->ndev = NULL; hi->addr[0] = 0L; hi->addr[1] = 0L; hi->addr_mapped[0] = 0L; @@ -309,7 +309,7 @@ c4hw_attach_all (void) if (!found) { pr_warning("No boards found\n"); - return ENODEV; + return -ENODEV; } /* sanity check for consistent hardware found */ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) @@ -318,7 +318,7 @@ c4hw_attach_all (void) { pr_warning("%s: something very wrong with pci_get_device\n", hi->devname); - return EIO; + return -EIO; } } /* bring board's memory regions on/line */ @@ -328,12 +328,12 @@ c4hw_attach_all (void) break; for (j = 0; j < 2; j++) { - if (request_mem_region (hi->addr[j], hi->len[j], hi->devname) == 0) + if (!request_mem_region (hi->addr[j], hi->len[j], hi->devname)) { pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n", hi->devname, hi->addr[j], hi->len[j]); cleanup_ioremap (); - return ENOMEM; + return -ENOMEM; } hi->addr_mapped[j] = (unsigned long) ioremap (hi->addr[j], hi->len[j]); if (!hi->addr_mapped[j]) @@ -341,7 +341,7 @@ c4hw_attach_all (void) pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", hi->devname, hi->addr[j], hi->len[j]); cleanup_ioremap (); - return ENOMEM; + return -ENOMEM; } #ifdef SBE_MAP_DEBUG pr_warning("%s: io remapped from phys %x to virt %x\n", @@ -365,7 +365,7 @@ c4hw_attach_all (void) hi->devname, i, hi->pci_slot); cleanup_devs (); cleanup_ioremap (); - return EIO; + return -EIO; } pci_set_master (hi->pdev[0]); pci_set_master (hi->pdev[1]); diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index 142691c8d8d1..9b483739881a 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -133,7 +133,7 @@ getuserbychan (int channum) mch_t *ch; ch = c4_find_chan (channum); - return ch ? ch->user : 0; + return ch ? ch->user : NULL; } @@ -230,7 +230,7 @@ c4_wq_port_init (mpi_t *pi) __func__, name, pi->portnum); /* RLD DEBUG */ #endif if (!(pi->wq_port = create_singlethread_workqueue (name))) - return ENOMEM; + return -ENOMEM; return 0; /* success */ } @@ -245,7 +245,7 @@ c4_wq_port_cleanup (mpi_t *pi) { destroy_workqueue (pi->wq_port); /* this also calls * flush_workqueue() */ - pi->wq_port = 0; + pi->wq_port = NULL; } } @@ -420,7 +420,7 @@ create_chan (struct net_device *ndev, ci_t *ci, int ret; if (c4_find_chan (cp->channum)) - return 0; /* channel already exists */ + return NULL; /* channel already exists */ { struct c4_priv *priv; @@ -430,14 +430,14 @@ create_chan (struct net_device *ndev, ci_t *ci, if (!priv) { pr_warning("%s: no memory for net_device !\n", ci->devname); - return 0; + return NULL; } dev = alloc_hdlcdev (priv); if (!dev) { pr_warning("%s: no memory for hdlc_device !\n", ci->devname); OS_kfree (priv); - return 0; + return NULL; } priv->ci = ci; priv->channum = cp->channum; @@ -496,7 +496,7 @@ create_chan (struct net_device *ndev, ci_t *ci, pr_info("%s: create_chan[%d] registration error = %d.\n", ci->devname, cp->channum, ret); free_netdev (dev); /* cleanup */ - return 0; /* failed to register */ + return NULL; /* failed to register */ } return dev; } @@ -744,7 +744,7 @@ do_deluser (struct net_device *ndev, int lockit) ch = c4_find_chan (channum); if (ch == NULL) return -ENOENT; - ch->user = 0; /* will be freed, below */ + ch->user = NULL; /* will be freed, below */ } if (lockit) @@ -959,7 +959,7 @@ c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, { pr_warning("%s: no memory for struct net_device !\n", hi->devname); error_flag = ENOMEM; - return 0; + return NULL; } ci = (ci_t *)(netdev_priv(ndev)); ndev->irq = irq0; @@ -970,7 +970,7 @@ c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, c4_list = ci; ci->brdno = ci->next ? ci->next->brdno + 1 : 0; - if (CI == 0) + if (!CI) CI = ci; /* DEBUG, only board 0 usage */ strcpy (ci->devname, hi->devname); @@ -996,7 +996,7 @@ c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, OS_kfree (netdev_priv(ndev)); OS_kfree (ndev); error_flag = ENODEV; - return 0; + return NULL; } /************************************************************* * int request_irq(unsigned int irq, @@ -1022,7 +1022,7 @@ c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, OS_kfree (netdev_priv(ndev)); OS_kfree (ndev); error_flag = EIO; - return 0; + return NULL; } #ifdef CONFIG_SBE_PMCC4_NCOMM if (request_irq (irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) @@ -1033,7 +1033,7 @@ c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, OS_kfree (netdev_priv(ndev)); OS_kfree (ndev); error_flag = EIO; - return 0; + return NULL; } #endif @@ -1091,7 +1091,7 @@ c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, free_irq (irq0, ndev); OS_kfree (netdev_priv(ndev)); OS_kfree (ndev); - return 0; /* failure, error_flag is set */ + return NULL; /* failure, error_flag is set */ } return ndev; } diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c index 52b6d7f5fd47..0ba8c3ae673b 100644 --- a/drivers/staging/cxt1e1/musycc.c +++ b/drivers/staging/cxt1e1/musycc.c @@ -745,8 +745,8 @@ musycc_init(ci_t *ci) #define INT_QUEUE_BOUNDARY 4 regaddr = OS_kmalloc((INT_QUEUE_SIZE + 1) * sizeof(u_int32_t)); - if (regaddr == 0) - return ENOMEM; + if (!regaddr) + return -ENOMEM; ci->iqd_p_saved = regaddr; /* save orig value for free's usage */ ci->iqd_p = (u_int32_t *) ((unsigned long) (regaddr + INT_QUEUE_BOUNDARY - 1) & (~(INT_QUEUE_BOUNDARY - 1))); /* this calculates @@ -766,13 +766,13 @@ musycc_init(ci_t *ci) #define GROUP_BOUNDARY 0x800 regaddr = OS_kmalloc(sizeof(struct musycc_groupr) + GROUP_BOUNDARY); - if (regaddr == 0) { + if (!regaddr) { for (gchan = 0; gchan < i; gchan++) { pi = &ci->port[gchan]; OS_kfree(pi->reg); - pi->reg = 0; + pi->reg = NULL; } - return ENOMEM; + return -ENOMEM; } pi->regram_saved = regaddr; /* save orig value for free's usage */ pi->regram = (struct musycc_groupr *) ((unsigned long) (regaddr + GROUP_BOUNDARY - 1) & @@ -839,12 +839,12 @@ musycc_bh_tx_eom(mpi_t *pi, int gchan) volatile u_int32_t status; ch = pi->chan[gchan]; - if (ch == 0 || ch->state != UP) { + if (!ch || ch->state != UP) { if (cxt1e1_log_level >= LOG_ERROR) pr_info("%s: intr: xmit EOM on uninitialized channel %d\n", pi->up->devname, gchan); } - if (ch == 0 || ch->mdt == 0) + if (!ch || !ch->mdt) return; /* note: mdt==0 implies a malloc() * failure w/in chan_up() routine */ @@ -907,7 +907,7 @@ musycc_bh_tx_eom(mpi_t *pi, int gchan) ch->txd_irq_srv = md->snext; md->data = 0; - if (md->mem_token != 0) { + if (md->mem_token) { /* upcount channel */ atomic_sub(OS_mem_token_tlen(md->mem_token), &ch->tx_pending); /* upcount card */ @@ -931,7 +931,7 @@ musycc_bh_tx_eom(mpi_t *pi, int gchan) #endif /*** CONFIG_SBE_WAN256T3_NCOMM ***/ OS_mem_token_free_irq(md->mem_token); - md->mem_token = 0; + md->mem_token = NULL; } md->status = 0; #ifdef RLD_TXFULL_DEBUG @@ -1012,13 +1012,13 @@ musycc_bh_rx_eom(mpi_t *pi, int gchan) u_int32_t error; ch = pi->chan[gchan]; - if (ch == 0 || ch->state != UP) { + if (!ch || ch->state != UP) { if (cxt1e1_log_level > LOG_ERROR) pr_info("%s: intr: receive EOM on uninitialized channel %d\n", pi->up->devname, gchan); return; } - if (ch->mdr == 0) + if (!ch->mdr) return; /* can this happen ? */ for (;;) { @@ -1566,18 +1566,18 @@ musycc_chan_down(ci_t *dummy, int channum) pi->regram->rmp[gchan] = 0; FLUSH_MEM_WRITE(); for (i = 0; i < ch->txd_num; i++) - if (ch->mdt[i].mem_token != 0) + if (ch->mdt[i].mem_token) OS_mem_token_free(ch->mdt[i].mem_token); for (i = 0; i < ch->rxd_num; i++) - if (ch->mdr[i].mem_token != 0) + if (ch->mdr[i].mem_token) OS_mem_token_free(ch->mdr[i].mem_token); OS_kfree(ch->mdr); - ch->mdr = 0; + ch->mdr = NULL; ch->rxd_num = 0; OS_kfree(ch->mdt); - ch->mdt = 0; + ch->mdt = NULL; ch->txd_num = 0; musycc_update_timeslots(pi); @@ -1746,7 +1746,7 @@ musycc_start_xmit(ci_t *ci, int channum, void *mem_token) #endif u |= (PADFILL_ENABLE | (ch->p.pad_fill_count << EXTRA_FLAGS)); } - md->mem_token = len ? 0 : mem_token; /* Fill in mds on last + md->mem_token = len ? NULL : mem_token; /* Fill in mds on last * segment, others set ZERO * so that entire token is * removed ONLY when ALL diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c index 2383c609bf39..4028ea11c442 100644 --- a/drivers/staging/cxt1e1/pmcc4_drv.c +++ b/drivers/staging/cxt1e1/pmcc4_drv.c @@ -70,7 +70,7 @@ extern void *memset (void *s, int c, size_t n); #endif int drvr_state = SBE_DRVR_INIT; -ci_t *c4_list = 0; +ci_t *c4_list = NULL; ci_t *CI; /* dummy pointer to board ZEROE's data - * DEBUG USAGE */ @@ -119,7 +119,7 @@ c4_find_chan (int channum) return ch; } } - return 0; + return NULL; } @@ -145,7 +145,7 @@ c4_new (void *hi) pr_warning("failed CI malloc, size %u.\n", (unsigned int) sizeof (ci_t)); - if (CI == 0) + if (!CI) CI = ci; /* DEBUG, only board 0 usage */ return ci; } @@ -831,7 +831,7 @@ c4_musycc_rw (ci_t *ci, struct c4_musycc_param *mcp) { mpi_t *pi; volatile u_int32_t *dph; /* hardware implemented register */ - u_int32_t *dpr = 0; /* RAM image of registers for group command + u_int32_t *dpr = NULL; /* RAM image of registers for group command * usage */ int offset = mcp->offset % 0x800; /* group relative address * offset, mcp->portnum is @@ -1060,7 +1060,7 @@ c4_new_chan (ci_t *ci, int portnum, int channum, void *user) } /* save off interface assignments which bound a board */ - if (ci->first_if == 0) /* first channel registered is assumed to + if (!ci->first_if) /* first channel registered is assumed to * be the lowest channel */ { ci->first_if = ci->last_if = user; @@ -1392,7 +1392,7 @@ c4_chan_up (ci_t *ci, int channum) md->status = HOST_TX_OWNED; /* Host owns TX descriptor ** CODING * NOTE: HOST_TX_OWNED = 0 so no need to * byteSwap */ - md->mem_token = 0; + md->mem_token = NULL; md->data = 0; if (i == (txnum - 1)) { @@ -1448,10 +1448,10 @@ errfree: OS_mem_token_free (ch->mdr[i].mem_token); } OS_kfree (ch->mdt); - ch->mdt = 0; + ch->mdt = NULL; ch->txd_num = 0; OS_kfree (ch->mdr); - ch->mdr = 0; + ch->mdr = NULL; ch->rxd_num = 0; ch->state = DOWN; return ENOBUFS; diff --git a/drivers/staging/cxt1e1/sbecom_inline_linux.h b/drivers/staging/cxt1e1/sbecom_inline_linux.h index 3c6d1c0fc6d6..ba3ff3efe063 100644 --- a/drivers/staging/cxt1e1/sbecom_inline_linux.h +++ b/drivers/staging/cxt1e1/sbecom_inline_linux.h @@ -73,7 +73,7 @@ OS_mem_token_alloc (size_t size) if (!skb) { //pr_warning("no mem in OS_mem_token_alloc !\n"); - return 0; + return NULL; } return skb; } @@ -103,7 +103,7 @@ OS_mem_token_data (void *token) static inline void * OS_mem_token_next (void *token) { - return 0; + return NULL; } diff --git a/drivers/staging/cxt1e1/sbecrc.c b/drivers/staging/cxt1e1/sbecrc.c index 87512a53f720..81fa8a3a462c 100644 --- a/drivers/staging/cxt1e1/sbecrc.c +++ b/drivers/staging/cxt1e1/sbecrc.c @@ -88,7 +88,7 @@ sbeCrc(u_int8_t *buffer, /* data buffer to crc */ u_int32_t initialCrc, /* starting CRC */ u_int32_t *result) { - u_int32_t *tbl = 0; + u_int32_t *tbl = NULL; u_int32_t temp1, temp2, crc; /* @@ -102,7 +102,7 @@ sbeCrc(u_int8_t *buffer, /* data buffer to crc */ genCrcTable(tbl); #else tbl = (u_int32_t *) OS_kmalloc(CRC_TABLE_ENTRIES * sizeof(u_int32_t)); - if (tbl == 0) { + if (!tbl) { *result = 0; /* dummy up return value due to malloc * failure */ return; diff --git a/drivers/staging/cxt1e1/sbeid.c b/drivers/staging/cxt1e1/sbeid.c index 791993fec96b..6ec51bccceb1 100644 --- a/drivers/staging/cxt1e1/sbeid.c +++ b/drivers/staging/cxt1e1/sbeid.c @@ -22,7 +22,7 @@ char * sbeid_get_bdname (ci_t *ci) { - char *np = 0; + char *np = NULL; switch (ci->brd_id) { diff --git a/drivers/staging/cxt1e1/sbeproc.c b/drivers/staging/cxt1e1/sbeproc.c index 9361dd8ce125..353c001d3fbe 100644 --- a/drivers/staging/cxt1e1/sbeproc.c +++ b/drivers/staging/cxt1e1/sbeproc.c @@ -44,7 +44,7 @@ void sbecom_proc_brd_cleanup(ci_t *ci) static void sbecom_proc_get_brdinfo(ci_t *ci, struct sbe_brd_info *bip) { hdw_info_t *hi = &hdw_info[ci->brdno]; - u_int8_t *bsn = 0; + u_int8_t *bsn = NULL; switch (hi->promfmt) { diff --git a/drivers/staging/cxt1e1/sbew_ioc.h b/drivers/staging/cxt1e1/sbew_ioc.h index ce9b15c71894..e1e5bfc9ad37 100644 --- a/drivers/staging/cxt1e1/sbew_ioc.h +++ b/drivers/staging/cxt1e1/sbew_ioc.h @@ -39,21 +39,21 @@ */ #define SBE_IOC_LOGLEVEL _IOW(SBE_IOC_MAGIC, 0x00, int) -#define SBE_IOC_CHAN_NEW _IOW(SBE_IOC_MAGIC, 0x01,int) /* unused */ -#define SBE_IOC_CHAN_UP _IOW(SBE_IOC_MAGIC, 0x02,int) /* unused */ -#define SBE_IOC_CHAN_DOWN _IOW(SBE_IOC_MAGIC, 0x03,int) /* unused */ -#define SBE_IOC_CHAN_GET _IOWR(SBE_IOC_MAGIC,0x04, struct sbecom_chan_param) +#define SBE_IOC_CHAN_NEW _IOW(SBE_IOC_MAGIC, 0x01, int) /* unused */ +#define SBE_IOC_CHAN_UP _IOW(SBE_IOC_MAGIC, 0x02, int) /* unused */ +#define SBE_IOC_CHAN_DOWN _IOW(SBE_IOC_MAGIC, 0x03, int) /* unused */ +#define SBE_IOC_CHAN_GET _IOWR(SBE_IOC_MAGIC, 0x04, struct sbecom_chan_param) #define SBE_IOC_CHAN_SET _IOW(SBE_IOC_MAGIC, 0x05, struct sbecom_chan_param) -#define SBE_IOC_CHAN_GET_STAT _IOWR(SBE_IOC_MAGIC,0x06, struct sbecom_chan_stats) +#define SBE_IOC_CHAN_GET_STAT _IOWR(SBE_IOC_MAGIC, 0x06, struct sbecom_chan_stats) #define SBE_IOC_CHAN_DEL_STAT _IOW(SBE_IOC_MAGIC, 0x07, int) #define SBE_IOC_PORTS_ENABLE _IOW(SBE_IOC_MAGIC, 0x0A, int) -#define SBE_IOC_PORT_GET _IOWR(SBE_IOC_MAGIC,0x0C, struct sbecom_port_param) +#define SBE_IOC_PORT_GET _IOWR(SBE_IOC_MAGIC, 0x0C, struct sbecom_port_param) #define SBE_IOC_PORT_SET _IOW(SBE_IOC_MAGIC, 0x0D, struct sbecom_port_param) -#define SBE_IOC_READ_VEC _IOWR(SBE_IOC_MAGIC,0x10, struct sbecom_wrt_vec) -#define SBE_IOC_WRITE_VEC _IOWR(SBE_IOC_MAGIC,0x11, struct sbecom_wrt_vec) +#define SBE_IOC_READ_VEC _IOWR(SBE_IOC_MAGIC, 0x10, struct sbecom_wrt_vec) +#define SBE_IOC_WRITE_VEC _IOWR(SBE_IOC_MAGIC, 0x11, struct sbecom_wrt_vec) #define SBE_IOC_GET_SN _IOR(SBE_IOC_MAGIC, 0x12, u_int32_t) #define SBE_IOC_RESET_DEV _IOW(SBE_IOC_MAGIC, 0x13, int) -#define SBE_IOC_FRAMER_GET _IOWR(SBE_IOC_MAGIC,0x14, struct sbecom_framer_param) +#define SBE_IOC_FRAMER_GET _IOWR(SBE_IOC_MAGIC, 0x14, struct sbecom_framer_param) #define SBE_IOC_FRAMER_SET _IOW(SBE_IOC_MAGIC, 0x15, struct sbecom_framer_param) #define SBE_IOC_CARD_GET _IOR(SBE_IOC_MAGIC, 0x20, struct sbecom_card_param) #define SBE_IOC_CARD_SET _IOW(SBE_IOC_MAGIC, 0x21, struct sbecom_card_param) @@ -61,13 +61,13 @@ #define SBE_IOC_CARD_DEL_STAT _IO(SBE_IOC_MAGIC, 0x23) #define SBE_IOC_CARD_CHAN_STAT _IOR(SBE_IOC_MAGIC, 0x24, struct sbecom_chan_stats) #define SBE_IOC_CARD_BLINK _IOW(SBE_IOC_MAGIC, 0x30, int) -#define SBE_IOC_DRVINFO_GET _IOWR(SBE_IOC_MAGIC,0x31, struct sbe_drv_info) +#define SBE_IOC_DRVINFO_GET _IOWR(SBE_IOC_MAGIC, 0x31, struct sbe_drv_info) #define SBE_IOC_BRDINFO_GET _IOR(SBE_IOC_MAGIC, 0x32, struct sbe_brd_info) -#define SBE_IOC_IID_GET _IOWR(SBE_IOC_MAGIC,0x33, struct sbe_iid_info) +#define SBE_IOC_IID_GET _IOWR(SBE_IOC_MAGIC, 0x33, struct sbe_iid_info) #define SBE_IOC_BRDADDR_GET _IOWR(SBE_IOC_MAGIC, 0x34, struct sbe_brd_addr) #ifdef NOT_YET_COMMON -#define SBE_IOC_TSIOC_GET _IOWR(SBE_IOC_MAGIC,0x16, struct wanc1t3_ts_param) +#define SBE_IOC_TSIOC_GET _IOWR(SBE_IOC_MAGIC, 0x16, struct wanc1t3_ts_param) #define SBE_IOC_TSIOC_SET _IOW(SBE_IOC_MAGIC, 0x17, struct wanc1t3_ts_param) #endif diff --git a/drivers/staging/dgap/Makefile b/drivers/staging/dgap/Makefile index 9f1fce157c77..3abe8d2bb748 100644 --- a/drivers/staging/dgap/Makefile +++ b/drivers/staging/dgap/Makefile @@ -1,5 +1,3 @@ -EXTRA_CFLAGS += -DDG_NAME=\"dgap-1.3-16\" -DDG_PART=\"40002347_C\" - obj-$(CONFIG_DGAP) += dgap.o diff --git a/drivers/staging/dgap/dgap_downld.h b/drivers/staging/dgap/dgap_downld.h index f79e65cd1d51..271ac19257f9 100644 --- a/drivers/staging/dgap/dgap_downld.h +++ b/drivers/staging/dgap/dgap_downld.h @@ -35,7 +35,7 @@ struct fepimg { int type; /* board type */ int len; /* length of image */ - char fepimage[1]; /* begining of image */ + char fepimage[1]; /* beginning of image */ }; struct downldio { diff --git a/drivers/staging/dgap/dgap_driver.c b/drivers/staging/dgap/dgap_driver.c index 40ef785a0428..4c1515ee56e5 100644 --- a/drivers/staging/dgap/dgap_driver.c +++ b/drivers/staging/dgap/dgap_driver.c @@ -32,16 +32,12 @@ #include <linux/kernel.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> /* For udelay */ #include <linux/slab.h> #include <asm/uaccess.h> /* For copy_from_user/copy_to_user */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) #include <linux/sched.h> -#endif #include "dgap_driver.h" #include "dgap_pci.h" @@ -420,8 +416,7 @@ void dgap_cleanup_module(void) unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); } - if (dgap_config_buf) - kfree(dgap_config_buf); + kfree(dgap_config_buf); for (i = 0; i < dgap_NumBoards; ++i) { dgap_remove_ports_sysfiles(dgap_Board[i]); @@ -488,10 +483,8 @@ static void dgap_cleanup_board(struct board_t *brd) } } - if (brd->flipbuf) - kfree(brd->flipbuf); - if (brd->flipflagbuf) - kfree(brd->flipflagbuf); + kfree(brd->flipbuf); + kfree(brd->flipflagbuf); dgap_Board[brd->boardnum] = NULL; diff --git a/drivers/staging/dgap/dgap_driver.h b/drivers/staging/dgap/dgap_driver.h index b1cf489a729c..7d631e80c00e 100644 --- a/drivers/staging/dgap/dgap_driver.h +++ b/drivers/staging/dgap/dgap_driver.h @@ -46,13 +46,16 @@ /* * Driver identification, error and debugging statments * - * In theory, you can change all occurances of "digi" in the next + * In theory, you can change all occurrences of "digi" in the next * three lines, and the driver printk's will all automagically change. * * APR((fmt, args, ...)); Always prints message * DPR((fmt, args, ...)); Only prints if DGAP_TRACER is defined at * compile time and dgap_debug!=0 */ +#define DG_NAME "dgap-1.3-16" +#define DG_PART "40002347_C" + #define PROCSTR "dgap" /* /proc entries */ #define DEVSTR "/dev/dg/dgap" /* /dev entries */ #define DRVSTR "dgap" /* Driver name string diff --git a/drivers/staging/dgap/dgap_fep5.c b/drivers/staging/dgap/dgap_fep5.c index 4464f02c9575..794cf9db8b83 100644 --- a/drivers/staging/dgap/dgap_fep5.c +++ b/drivers/staging/dgap/dgap_fep5.c @@ -134,7 +134,7 @@ int dgap_after_config_loaded(void) dgap_Board[i]->flipflagbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC); } - return (rc); + return rc; } @@ -150,14 +150,14 @@ static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *fro int n = U2BSIZE; if (!brd || brd->magic != DGAP_BOARD_MAGIC) - return(-EFAULT); + return -EFAULT; while (len) { if (n > len) n = len; if (copy_from_user((char *) &buf, from_addr, n) == -1 ) { - return(-EFAULT); + return -EFAULT; } /* Copy data from buffer to card memory */ @@ -169,7 +169,7 @@ static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *fro from_addr += n; n = U2BSIZE; } - return(0); + return 0; } @@ -1155,20 +1155,20 @@ uint dgap_get_custom_baud(struct channel_t *ch) uint value = 0; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) { - return (0); + return 0; } if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC) { - return (0); + return 0; } if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS)) - return (0); + return 0; vaddr = ch->ch_bd->re_map_membase; if (!vaddr) - return (0); + return 0; /* * Go get from fep mem, what the fep @@ -1178,7 +1178,7 @@ uint dgap_get_custom_baud(struct channel_t *ch) (ch->ch_portnum * 0x28) + LINE_SPEED)); value = readw(vaddr + offset); - return (value); + return value; } @@ -1229,29 +1229,24 @@ int dgap_param(struct tty_struct *tty) uchar mval; uchar hflow; - if (!tty || tty->magic != TTY_MAGIC) { - return (-ENXIO); - } + if (!tty || tty->magic != TTY_MAGIC) + return -ENXIO; un = (struct un_t *) tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) { - return (-ENXIO); - } + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -ENXIO; ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) { - return (-ENXIO); - } + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -ENXIO; bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) { - return (-ENXIO); - } + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -ENXIO; bs = ch->ch_bs; - if (bs == 0) { - return (-ENXIO); - } + if (!bs) + return -ENXIO; DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n", ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag)); @@ -1558,7 +1553,7 @@ int dgap_param(struct tty_struct *tty) DPR_PARAM(("param finish\n")); - return (0); + return 0; } @@ -1675,7 +1670,7 @@ static int dgap_event(struct board_t *bd) int b1; if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-ENXIO); + return -ENXIO; DGAP_LOCK(bd->bd_lock, lock_flags); @@ -1683,7 +1678,7 @@ static int dgap_event(struct board_t *bd) if (!vaddr) { DGAP_UNLOCK(bd->bd_lock, lock_flags); - return (-ENXIO); + return -ENXIO; } eaddr = (struct ev_t *) (vaddr + EVBUF); @@ -1701,7 +1696,7 @@ static int dgap_event(struct board_t *bd) DPR_EVENT(("should be calling xxfail %d\n", __LINE__)); /* Let go of board lock */ DGAP_UNLOCK(bd->bd_lock, lock_flags); - return (-ENXIO); + return -ENXIO; } /* @@ -1949,5 +1944,5 @@ next: writew(tail, &(eaddr->ev_tail)); DGAP_UNLOCK(bd->bd_lock, lock_flags); - return (0); + return 0; } diff --git a/drivers/staging/dgap/dgap_fep5.h b/drivers/staging/dgap/dgap_fep5.h index 3a12ba5e3c2a..c9abc406a1e0 100644 --- a/drivers/staging/dgap/dgap_fep5.h +++ b/drivers/staging/dgap/dgap_fep5.h @@ -211,7 +211,7 @@ struct bs_t { #define SIFLAG 0xea /* Set UNIX iflags */ #define SFLOWC 0xeb /* Set flow control characters */ #define STLOW 0xec /* Set transmit low water mark */ -#define RPAUSE 0xee /* Pause recieve */ +#define RPAUSE 0xee /* Pause receive */ #define RRESUME 0xef /* Resume receive */ #define CHRESET 0xf0 /* Reset Channel */ #define BUFSETALL 0xf2 /* Set Tx & Rx buffer size avail*/ diff --git a/drivers/staging/dgap/dgap_kcompat.h b/drivers/staging/dgap/dgap_kcompat.h index 8ebf4b7373b7..0dc2404922ff 100644 --- a/drivers/staging/dgap/dgap_kcompat.h +++ b/drivers/staging/dgap/dgap_kcompat.h @@ -28,11 +28,6 @@ #ifndef __DGAP_KCOMPAT_H #define __DGAP_KCOMPAT_H -# ifndef KERNEL_VERSION -# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -# endif - - #if !defined(TTY_FLIPBUF_SIZE) # define TTY_FLIPBUF_SIZE 512 #endif @@ -66,28 +61,4 @@ module_param(VAR, long, PERM); \ MODULE_PARM_DESC(VAR, DESC); - - - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - - - - -/* NOTHING YET */ - - - - -# else - - - -# error "this driver does not support anything below the 2.6.27 kernel series." - - - -# endif - #endif /* ! __DGAP_KCOMPAT_H */ diff --git a/drivers/staging/dgap/dgap_parse.c b/drivers/staging/dgap/dgap_parse.c index 5497e6de0608..ff9d19449b43 100644 --- a/drivers/staging/dgap/dgap_parse.c +++ b/drivers/staging/dgap/dgap_parse.c @@ -904,7 +904,7 @@ int dgap_parsefile(char **in, int Remove) /* * dgap_sindex: much like index(), but it looks for a match of any character in * the group, and returns that position. If the first character is a ^, then - * this will match the first occurence not in that group. + * this will match the first occurrence not in that group. */ static char *dgap_sindex (char *string, char *group) { @@ -1013,8 +1013,10 @@ static void dgap_err(char *s) static struct cnode *dgap_newnode(int t) { struct cnode *n; - if ( (n = (struct cnode *) kmalloc(sizeof(struct cnode ), GFP_ATOMIC) ) != NULL) { - memset( (char *)n, 0, sizeof(struct cnode ) ); + + n = kmalloc(sizeof(struct cnode), GFP_ATOMIC); + if (n != NULL) { + memset((char *)n, 0, sizeof(struct cnode)); n->type = t; } return(n); @@ -1150,7 +1152,7 @@ uint dgap_config_get_altpin(struct board_t *bd) /* * Given a specific type of board, if found, detached link and - * returns the first occurance in the list. + * returns the first occurrence in the list. */ struct cnode *dgap_find_config(int type, int bus, int slot) { diff --git a/drivers/staging/dgap/dgap_sysfs.c b/drivers/staging/dgap/dgap_sysfs.c index 94da06fcf7e9..7f4ec9a18293 100644 --- a/drivers/staging/dgap/dgap_sysfs.c +++ b/drivers/staging/dgap/dgap_sysfs.c @@ -395,7 +395,7 @@ static ssize_t dgap_tty_state_show(struct device *d, struct device_attribute *at if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -420,7 +420,7 @@ static ssize_t dgap_tty_baud_show(struct device *d, struct device_attribute *att if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -445,7 +445,7 @@ static ssize_t dgap_tty_msignals_show(struct device *d, struct device_attribute if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -479,7 +479,7 @@ static ssize_t dgap_tty_iflag_show(struct device *d, struct device_attribute *at if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -504,7 +504,7 @@ static ssize_t dgap_tty_cflag_show(struct device *d, struct device_attribute *at if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -529,7 +529,7 @@ static ssize_t dgap_tty_oflag_show(struct device *d, struct device_attribute *at if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -554,7 +554,7 @@ static ssize_t dgap_tty_lflag_show(struct device *d, struct device_attribute *at if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -579,7 +579,7 @@ static ssize_t dgap_tty_digi_flag_show(struct device *d, struct device_attribute if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -604,7 +604,7 @@ static ssize_t dgap_tty_rxcount_show(struct device *d, struct device_attribute * if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -629,7 +629,7 @@ static ssize_t dgap_tty_txcount_show(struct device *d, struct device_attribute * if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; @@ -661,7 +661,7 @@ static ssize_t dgap_tty_name_show(struct device *d, struct device_attribute *att if (!d) return (0); - un = (struct un_t *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; diff --git a/drivers/staging/dgap/dgap_tty.c b/drivers/staging/dgap/dgap_tty.c index b906db30b617..2a7a37298da4 100644 --- a/drivers/staging/dgap/dgap_tty.c +++ b/drivers/staging/dgap/dgap_tty.c @@ -249,7 +249,7 @@ int dgap_tty_register(struct board_t *brd) /* * If we're doing transparent print, we have to do all of the above - * again, seperately so we don't get the LD confused about what major + * again, separately so we don't get the LD confused about what major * we are when we get into the dgap_tty_open() routine. */ brd->PrintDriver = alloc_tty_driver(MAXPORTS); @@ -497,10 +497,8 @@ int dgap_tty_init(struct board_t *brd) */ void dgap_tty_post_uninit(void) { - if (dgap_TmpWriteBuf) { - kfree(dgap_TmpWriteBuf); - dgap_TmpWriteBuf = NULL; - } + kfree(dgap_TmpWriteBuf); + dgap_TmpWriteBuf = NULL; } @@ -522,10 +520,8 @@ void dgap_tty_uninit(struct board_t *brd) tty_unregister_device(brd->SerialDriver, i); } tty_unregister_driver(brd->SerialDriver); - if (brd->SerialDriver->ttys) { - kfree(brd->SerialDriver->ttys); - brd->SerialDriver->ttys = NULL; - } + kfree(brd->SerialDriver->ttys); + brd->SerialDriver->ttys = NULL; put_tty_driver(brd->SerialDriver); brd->dgap_Major_Serial_Registered = FALSE; } @@ -538,10 +534,8 @@ void dgap_tty_uninit(struct board_t *brd) tty_unregister_device(brd->PrintDriver, i); } tty_unregister_driver(brd->PrintDriver); - if (brd->PrintDriver->ttys) { - kfree(brd->PrintDriver->ttys); - brd->PrintDriver->ttys = NULL; - } + kfree(brd->PrintDriver->ttys); + brd->PrintDriver->ttys = NULL; put_tty_driver(brd->PrintDriver); brd->dgap_Major_TransparentPrint_Registered = FALSE; } @@ -601,7 +595,7 @@ static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *b /* * Loop while data remains. */ - while (nbuf > 0 && ch->ch_sniff_buf != 0) { + while (nbuf > 0 && ch->ch_sniff_buf) { /* * Determine the amount of available space left in the * buffer. If there's none, wait until some appears. @@ -1069,7 +1063,7 @@ static int dgap_tty_open(struct tty_struct *tty, struct file *file) DGAP_LOCK(brd->bd_lock, lock_flags); - /* The wait above should guarentee this cannot happen */ + /* The wait above should guarantee this cannot happen */ if (brd->state != BOARD_READY) { DGAP_UNLOCK(brd->bd_lock, lock_flags); return -ENXIO; @@ -1113,9 +1107,10 @@ static int dgap_tty_open(struct tty_struct *tty, struct file *file) MAJOR(tty_devnum(tty)), MINOR(tty_devnum(tty)), un, brd->name)); /* - * Error if channel info pointer is 0. + * Error if channel info pointer is NULL. */ - if ((bs = ch->ch_bs) == 0) { + bs = ch->ch_bs; + if (!bs) { DGAP_UNLOCK(ch->ch_lock, lock_flags2); DGAP_UNLOCK(brd->bd_lock, lock_flags); DPR_OPEN(("%d BS is 0!\n", __LINE__)); @@ -3513,10 +3508,6 @@ static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, return(-EINVAL); } - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(-ENOIOCTLCMD); - case DIGI_GETA: /* get information for ditty */ DGAP_UNLOCK(ch->ch_lock, lock_flags2); @@ -3586,12 +3577,4 @@ static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, return(-ENOIOCTLCMD); } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl end - cmd %s (%x), arg %lx\n", - dgap_ioctl_name(cmd), cmd, arg)); - - return(0); } diff --git a/drivers/staging/dgap/digi.h b/drivers/staging/dgap/digi.h index 651e2e5e93c7..bcea4f734a32 100644 --- a/drivers/staging/dgap/digi.h +++ b/drivers/staging/dgap/digi.h @@ -203,9 +203,9 @@ struct shrink_buf_struct { unsigned long shrink_buf_vaddr; /* Virtual address of board */ unsigned long shrink_buf_phys; /* Physical address of board */ unsigned long shrink_buf_bseg; /* Amount of board memory */ - unsigned long shrink_buf_hseg; /* '186 Begining of Dual-Port */ + unsigned long shrink_buf_hseg; /* '186 Beginning of Dual-Port */ - unsigned long shrink_buf_lseg; /* '186 Begining of freed memory */ + unsigned long shrink_buf_lseg; /* '186 Beginning of freed memory */ unsigned long shrink_buf_mseg; /* Linear address from start of dual-port were freed memory begins, host viewpoint. */ diff --git a/drivers/staging/dgap/downld.c b/drivers/staging/dgap/downld.c index 57dfd6bafcf6..638c5da43c85 100644 --- a/drivers/staging/dgap/downld.c +++ b/drivers/staging/dgap/downld.c @@ -52,7 +52,7 @@ char *pgm; void myperror(); /* -** This structure is used to keep track of the diferent images available +** This structure is used to keep track of the different images available ** to give to the driver. It is arranged so that the things that are ** constants or that have defaults are first inthe strucutre to simplify ** the table of initializers. @@ -789,7 +789,7 @@ int main(int argc, char **argv) /* ** myperror() ** -** Same as normal perror(), but places the program name at the begining +** Same as normal perror(), but places the program name at the beginning ** of the message. */ void myperror(char *s) diff --git a/drivers/staging/dgnc/dgnc_cls.c b/drivers/staging/dgnc/dgnc_cls.c index 117e15808240..fdc1aabc7fde 100644 --- a/drivers/staging/dgnc/dgnc_cls.c +++ b/drivers/staging/dgnc/dgnc_cls.c @@ -33,7 +33,7 @@ #include <linux/sched.h> /* For jiffies, task states */ #include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */ #include <linux/delay.h> /* For udelay */ -#include <asm/io.h> /* For read[bwl]/write[bwl] */ +#include <linux/io.h> /* For read[bwl]/write[bwl] */ #include <linux/serial.h> /* For struct async_serial */ #include <linux/serial_reg.h> /* For the various UART offsets */ #include <linux/pci.h> @@ -43,7 +43,7 @@ #include "dgnc_tty.h" #include "dgnc_trace.h" -static inline void cls_parse_isr(struct board_t *brd, uint port); +static inline void cls_parse_isr(struct dgnc_board *brd, uint port); static inline void cls_clear_break(struct channel_t *ch, int force); static inline void cls_set_cts_flow_control(struct channel_t *ch); static inline void cls_set_rts_flow_control(struct channel_t *ch); @@ -53,7 +53,7 @@ static inline void cls_set_no_output_flow_control(struct channel_t *ch); static inline void cls_set_no_input_flow_control(struct channel_t *ch); static void cls_parse_modem(struct channel_t *ch, uchar signals); static void cls_tasklet(unsigned long data); -static void cls_vpd(struct board_t *brd); +static void cls_vpd(struct dgnc_board *brd); static void cls_uart_init(struct channel_t *ch); static void cls_uart_off(struct channel_t *ch); static int cls_drain(struct tty_struct *tty, uint seconds); @@ -393,7 +393,7 @@ static inline void cls_clear_break(struct channel_t *ch, int force) /* Parse the ISR register for the specific port */ -static inline void cls_parse_isr(struct board_t *brd, uint port) +static inline void cls_parse_isr(struct dgnc_board *brd, uint port) { struct channel_t *ch; uchar isr = 0; @@ -417,9 +417,8 @@ static inline void cls_parse_isr(struct board_t *brd, uint port) isr = readb(&ch->ch_cls_uart->isr_fcr); /* Bail if no pending interrupt on port */ - if (isr & UART_IIR_NO_INT) { + if (isr & UART_IIR_NO_INT) break; - } DPR_INTR(("%s:%d port: %x isr: %x\n", __FILE__, __LINE__, port, isr)); @@ -444,9 +443,8 @@ static inline void cls_parse_isr(struct board_t *brd, uint port) } /* Received Xoff signal/Special character */ - if (isr & UART_IIR_XOFF) { + if (isr & UART_IIR_XOFF) /* Empty */ - } /* CTS/RTS change of state */ if (isr & UART_IIR_CTSRTS) { @@ -477,28 +475,24 @@ static void cls_param(struct tty_struct *tty) uchar uart_ier = 0; uint baud = 9600; int quot = 0; - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; - if (!tty || tty->magic != TTY_MAGIC) { + if (!tty || tty->magic != TTY_MAGIC) return; - } un = (struct un_t *) tty->driver_data; - if (!un || un->magic != DGNC_UNIT_MAGIC) { + if (!un || un->magic != DGNC_UNIT_MAGIC) return; - } ch = un->un_ch; - if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) { + if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) return; - } bd = ch->ch_bd; - if (!bd || bd->magic != DGNC_BOARD_MAGIC) { + if (!bd || bd->magic != DGNC_BOARD_MAGIC) return; - } DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n", ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag)); @@ -725,7 +719,7 @@ static void cls_param(struct tty_struct *tty) */ static void cls_tasklet(unsigned long data) { - struct board_t *bd = (struct board_t *) data; + struct dgnc_board *bd = (struct dgnc_board *) data; struct channel_t *ch; ulong lock_flags; int i; @@ -802,7 +796,7 @@ static void cls_tasklet(unsigned long data) */ static irqreturn_t cls_intr(int irq, void *voidbrd) { - struct board_t *brd = (struct board_t *) voidbrd; + struct dgnc_board *brd = (struct dgnc_board *) voidbrd; uint i = 0; uchar poll_reg; unsigned long lock_flags; @@ -976,17 +970,17 @@ static int cls_drain(struct tty_struct *tty, uint seconds) int rc = 0; if (!tty || tty->magic != TTY_MAGIC) { - return (-ENXIO); + return -ENXIO; } un = (struct un_t *) tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) { - return (-ENXIO); + return -ENXIO; } ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) { - return (-ENXIO); + return -ENXIO; } DGNC_LOCK(ch->ch_lock, lock_flags); @@ -1002,7 +996,7 @@ static int cls_drain(struct tty_struct *tty, uint seconds) if (rc) DPR_IOCTL(("%d Drain - User ctrl c'ed\n", __LINE__)); - return (rc); + return rc; } @@ -1305,9 +1299,8 @@ static uint cls_get_uart_bytes_left(struct channel_t *ch) /* Determine whether the Transmitter is empty or not */ if (!(lsr & UART_LSR_TEMT)) { - if (ch->ch_flags & CH_TX_FIFO_EMPTY) { + if (ch->ch_flags & CH_TX_FIFO_EMPTY) tasklet_schedule(&ch->ch_bd->helper_tasklet); - } left = 1; } else { @@ -1378,7 +1371,7 @@ static void cls_send_immediate_char(struct channel_t *ch, unsigned char c) writeb(c, &ch->ch_cls_uart->txrx); } -static void cls_vpd(struct board_t *brd) +static void cls_vpd(struct dgnc_board *brd) { ulong vpdbase; /* Start of io base of the card */ u8 __iomem *re_map_vpdbase;/* Remapped memory of the card */ diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c index 71d2b83cc3a1..4271fa38a46c 100644 --- a/drivers/staging/dgnc/dgnc_driver.c +++ b/drivers/staging/dgnc/dgnc_driver.c @@ -31,15 +31,10 @@ #include <linux/kernel.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/slab.h> - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) #include <linux/sched.h> -#endif - #include "dgnc_driver.h" #include "dgnc_pci.h" #include "dpacompat.h" @@ -71,16 +66,16 @@ PARM_INT(trcbuf_size, 0x100000, 0644, "Debugging trace buffer size."); * */ static int dgnc_start(void); -static int dgnc_finalize_board_init(struct board_t *brd); +static int dgnc_finalize_board_init(struct dgnc_board *brd); static void dgnc_init_globals(void); static int dgnc_found_board(struct pci_dev *pdev, int id); -static void dgnc_cleanup_board(struct board_t *brd); +static void dgnc_cleanup_board(struct dgnc_board *brd); static void dgnc_poll_handler(ulong dummy); static int dgnc_init_pci(void); static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static void dgnc_remove_one(struct pci_dev *dev); static int dgnc_probe1(struct pci_dev *pdev, int card_type); -static void dgnc_do_remap(struct board_t *brd); +static void dgnc_do_remap(struct dgnc_board *brd); /* Driver load/unload functions */ int dgnc_init_module(void); @@ -106,7 +101,7 @@ static struct file_operations dgnc_BoardFops = * Globals */ uint dgnc_NumBoards; -struct board_t *dgnc_Board[MAXBOARDS]; +struct dgnc_board *dgnc_Board[MAXBOARDS]; DEFINE_SPINLOCK(dgnc_global_lock); int dgnc_driver_state = DRIVER_INITIALIZED; ulong dgnc_poll_counter; @@ -225,7 +220,7 @@ int dgnc_init_module(void) rc = dgnc_start(); if (rc < 0) { - return(rc); + return rc; } /* @@ -250,7 +245,7 @@ int dgnc_init_module(void) } DPR_INIT(("Finished init_module. Returning %d\n", rc)); - return (rc); + return rc; } @@ -286,21 +281,14 @@ static int dgnc_start(void) if (rc <= 0) { APR(("Can't register dgnc driver device (%d)\n", rc)); rc = -ENXIO; - return(rc); + return rc; } dgnc_Major = rc; dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt"); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - device_create_drvdata(dgnc_class, NULL, - MKDEV(dgnc_Major, 0), - NULL, "dgnc_mgmt"); -#else device_create(dgnc_class, NULL, MKDEV(dgnc_Major, 0), NULL, "dgnc_mgmt"); -#endif - dgnc_Major_Control_Registered = TRUE; } @@ -311,7 +299,7 @@ static int dgnc_start(void) if (rc < 0) { APR(("tty preinit - not enough memory (%d)\n", rc)); - return(rc); + return rc; } /* Start the poller */ @@ -328,7 +316,7 @@ static int dgnc_start(void) dgnc_driver_state = DRIVER_READY; } - return(rc); + return rc; } /* @@ -418,7 +406,7 @@ void dgnc_cleanup_module(void) * * Free all the memory associated with a board */ -static void dgnc_cleanup_board(struct board_t *brd) +static void dgnc_cleanup_board(struct dgnc_board *brd) { int i = 0; @@ -491,7 +479,7 @@ static void dgnc_cleanup_board(struct board_t *brd) */ static int dgnc_found_board(struct pci_dev *pdev, int id) { - struct board_t *brd; + struct dgnc_board *brd; unsigned int pci_irq; int i = 0; int rc = 0; @@ -499,19 +487,19 @@ static int dgnc_found_board(struct pci_dev *pdev, int id) /* get the board structure and prep it */ brd = dgnc_Board[dgnc_NumBoards] = - (struct board_t *) kzalloc(sizeof(struct board_t), GFP_KERNEL); + kzalloc(sizeof(*brd), GFP_KERNEL); if (!brd) { APR(("memory allocation for board structure failed\n")); - return(-ENOMEM); + return -ENOMEM; } /* make a temporary message buffer for the boot messages */ brd->msgbuf = brd->msgbuf_head = - (char *) kzalloc(sizeof(char) * 8192, GFP_KERNEL); + kzalloc(sizeof(u8) * 8192, GFP_KERNEL); if (!brd->msgbuf) { kfree(brd); APR(("memory allocation for board msgbuf failed\n")); - return(-ENOMEM); + return -ENOMEM; } /* store the info for the board we've found */ @@ -663,7 +651,7 @@ static int dgnc_found_board(struct pci_dev *pdev, int id) default: APR(("Did not find any compatible Neo or Classic PCI boards in system.\n")); - return (-ENXIO); + return -ENXIO; } @@ -725,22 +713,22 @@ static int dgnc_found_board(struct pci_dev *pdev, int id) wake_up_interruptible(&brd->state_wait); - return(0); + return 0; failed: - return (-ENXIO); + return -ENXIO; } -static int dgnc_finalize_board_init(struct board_t *brd) { +static int dgnc_finalize_board_init(struct dgnc_board *brd) { int rc = 0; DPR_INIT(("dgnc_finalize_board_init() - start\n")); if (!brd || brd->magic != DGNC_BOARD_MAGIC) - return(-ENODEV); + return -ENODEV; DPR_INIT(("dgnc_finalize_board_init() - start #2\n")); @@ -756,13 +744,13 @@ static int dgnc_finalize_board_init(struct board_t *brd) { DPR_INIT(("Requested and received usage of IRQ %d\n", brd->irq)); } } - return(rc); + return rc; } /* * Remap PCI memory. */ -static void dgnc_do_remap(struct board_t *brd) +static void dgnc_do_remap(struct dgnc_board *brd) { if (!brd || brd->magic != DGNC_BOARD_MAGIC) @@ -802,7 +790,7 @@ static void dgnc_do_remap(struct board_t *brd) static void dgnc_poll_handler(ulong dummy) { - struct board_t *brd; + struct dgnc_board *brd; unsigned long lock_flags; int i; unsigned long new_time; @@ -900,7 +888,7 @@ int dgnc_ms_sleep(ulong ms) { current->state = TASK_INTERRUPTIBLE; schedule_timeout((ms * HZ) / 1000); - return (signal_pending(current)); + return signal_pending(current); } @@ -912,47 +900,47 @@ char *dgnc_ioctl_name(int cmd) { switch(cmd) { - case TCGETA: return("TCGETA"); - case TCGETS: return("TCGETS"); - case TCSETA: return("TCSETA"); - case TCSETS: return("TCSETS"); - case TCSETAW: return("TCSETAW"); - case TCSETSW: return("TCSETSW"); - case TCSETAF: return("TCSETAF"); - case TCSETSF: return("TCSETSF"); - case TCSBRK: return("TCSBRK"); - case TCXONC: return("TCXONC"); - case TCFLSH: return("TCFLSH"); - case TIOCGSID: return("TIOCGSID"); - - case TIOCGETD: return("TIOCGETD"); - case TIOCSETD: return("TIOCSETD"); - case TIOCGWINSZ: return("TIOCGWINSZ"); - case TIOCSWINSZ: return("TIOCSWINSZ"); - - case TIOCMGET: return("TIOCMGET"); - case TIOCMSET: return("TIOCMSET"); - case TIOCMBIS: return("TIOCMBIS"); - case TIOCMBIC: return("TIOCMBIC"); + case TCGETA: return "TCGETA"; + case TCGETS: return "TCGETS"; + case TCSETA: return "TCSETA"; + case TCSETS: return "TCSETS"; + case TCSETAW: return "TCSETAW"; + case TCSETSW: return "TCSETSW"; + case TCSETAF: return "TCSETAF"; + case TCSETSF: return "TCSETSF"; + case TCSBRK: return "TCSBRK"; + case TCXONC: return "TCXONC"; + case TCFLSH: return "TCFLSH"; + case TIOCGSID: return "TIOCGSID"; + + case TIOCGETD: return "TIOCGETD"; + case TIOCSETD: return "TIOCSETD"; + case TIOCGWINSZ: return "TIOCGWINSZ"; + case TIOCSWINSZ: return "TIOCSWINSZ"; + + case TIOCMGET: return "TIOCMGET"; + case TIOCMSET: return "TIOCMSET"; + case TIOCMBIS: return "TIOCMBIS"; + case TIOCMBIC: return "TIOCMBIC"; /* from digi.h */ - case DIGI_SETA: return("DIGI_SETA"); - case DIGI_SETAW: return("DIGI_SETAW"); - case DIGI_SETAF: return("DIGI_SETAF"); - case DIGI_SETFLOW: return("DIGI_SETFLOW"); - case DIGI_SETAFLOW: return("DIGI_SETAFLOW"); - case DIGI_GETFLOW: return("DIGI_GETFLOW"); - case DIGI_GETAFLOW: return("DIGI_GETAFLOW"); - case DIGI_GETA: return("DIGI_GETA"); - case DIGI_GEDELAY: return("DIGI_GEDELAY"); - case DIGI_SEDELAY: return("DIGI_SEDELAY"); - case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD"); - case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD"); - case TIOCMODG: return("TIOCMODG"); - case TIOCMODS: return("TIOCMODS"); - case TIOCSDTR: return("TIOCSDTR"); - case TIOCCDTR: return("TIOCCDTR"); - - default: return("unknown"); + case DIGI_SETA: return "DIGI_SETA"; + case DIGI_SETAW: return "DIGI_SETAW"; + case DIGI_SETAF: return "DIGI_SETAF"; + case DIGI_SETFLOW: return "DIGI_SETFLOW"; + case DIGI_SETAFLOW: return "DIGI_SETAFLOW"; + case DIGI_GETFLOW: return "DIGI_GETFLOW"; + case DIGI_GETAFLOW: return "DIGI_GETAFLOW"; + case DIGI_GETA: return "DIGI_GETA"; + case DIGI_GEDELAY: return "DIGI_GEDELAY"; + case DIGI_SEDELAY: return "DIGI_SEDELAY"; + case DIGI_GETCUSTOMBAUD: return "DIGI_GETCUSTOMBAUD"; + case DIGI_SETCUSTOMBAUD: return "DIGI_SETCUSTOMBAUD"; + case TIOCMODG: return "TIOCMODG"; + case TIOCMODS: return "TIOCMODS"; + case TIOCSDTR: return "TIOCSDTR"; + case TIOCCDTR: return "TIOCCDTR"; + + default: return "unknown"; } } diff --git a/drivers/staging/dgnc/dgnc_driver.h b/drivers/staging/dgnc/dgnc_driver.h index 218b15dccb7d..3519b803e753 100644 --- a/drivers/staging/dgnc/dgnc_driver.h +++ b/drivers/staging/dgnc/dgnc_driver.h @@ -45,7 +45,7 @@ /* * Driver identification, error and debugging statments * - * In theory, you can change all occurances of "digi" in the next + * In theory, you can change all occurrences of "digi" in the next * three lines, and the driver printk's will all automagically change. * * APR((fmt, args, ...)); Always prints message @@ -246,7 +246,7 @@ enum { * *************************************************************************/ -struct board_t; +struct dgnc_board; struct channel_t; /************************************************************************ @@ -259,7 +259,7 @@ struct board_ops { void (*uart_off) (struct channel_t *ch); int (*drain) (struct tty_struct *tty, uint seconds); void (*param) (struct tty_struct *tty); - void (*vpd) (struct board_t *brd); + void (*vpd) (struct dgnc_board *brd); void (*assert_modem_signals) (struct channel_t *ch); void (*flush_uart_write) (struct channel_t *ch); void (*flush_uart_read) (struct channel_t *ch); @@ -282,7 +282,7 @@ struct board_ops { /* * Per-board information */ -struct board_t { +struct dgnc_board { int magic; /* Board Magic number. */ int boardnum; /* Board number: 0-32 */ @@ -449,7 +449,7 @@ struct un_t { ************************************************************************/ struct channel_t { int magic; /* Channel Magic Number */ - struct board_t *ch_bd; /* Board structure pointer */ + struct dgnc_board *ch_bd; /* Board structure pointer */ struct digi_t ch_digi; /* Transparent Print structure */ struct un_t ch_tun; /* Terminal unit info */ struct un_t ch_pun; /* Printer unit info */ @@ -555,7 +555,7 @@ extern int dgnc_poll_tick; /* Poll interval - 20 ms */ extern int dgnc_trcbuf_size; /* Size of the ringbuffer */ extern spinlock_t dgnc_global_lock; /* Driver global spinlock */ extern uint dgnc_NumBoards; /* Total number of boards */ -extern struct board_t *dgnc_Board[MAXBOARDS]; /* Array of board structs */ +extern struct dgnc_board *dgnc_Board[MAXBOARDS]; /* Array of board structs */ extern ulong dgnc_poll_counter; /* Times the poller has run */ extern char *dgnc_state_text[]; /* Array of state text */ extern char *dgnc_driver_state_text[];/* Array of driver state text */ diff --git a/drivers/staging/dgnc/dgnc_kcompat.h b/drivers/staging/dgnc/dgnc_kcompat.h index 00f589a13ab9..eaec7e6a28e1 100644 --- a/drivers/staging/dgnc/dgnc_kcompat.h +++ b/drivers/staging/dgnc/dgnc_kcompat.h @@ -28,13 +28,6 @@ #ifndef __DGNC_KCOMPAT_H #define __DGNC_KCOMPAT_H -#include <linux/version.h> - -# ifndef KERNEL_VERSION -# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -# endif - - #if !defined(TTY_FLIPBUF_SIZE) # define TTY_FLIPBUF_SIZE 512 #endif @@ -68,26 +61,4 @@ module_param(VAR, long, PERM); \ MODULE_PARM_DESC(VAR, DESC); - - - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - - - -/* NOTHING YET */ - - - -# else - - - -# error "this driver does not support anything below the 2.6.27 kernel series." - - - -# endif - #endif /* ! __DGNC_KCOMPAT_H */ diff --git a/drivers/staging/dgnc/dgnc_mgmt.c b/drivers/staging/dgnc/dgnc_mgmt.c index c4629d7c80b2..354458c5068e 100644 --- a/drivers/staging/dgnc/dgnc_mgmt.c +++ b/drivers/staging/dgnc/dgnc_mgmt.c @@ -74,13 +74,13 @@ int dgnc_mgmt_open(struct inode *inode, struct file *file) /* Only allow 1 open at a time on mgmt device */ if (dgnc_mgmt_in_use[minor]) { DGNC_UNLOCK(dgnc_global_lock, lock_flags); - return (-EBUSY); + return -EBUSY; } dgnc_mgmt_in_use[minor]++; } else { DGNC_UNLOCK(dgnc_global_lock, lock_flags); - return (-ENXIO); + return -ENXIO; } DGNC_UNLOCK(dgnc_global_lock, lock_flags); @@ -154,7 +154,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ddi.dinfo_nboards, ddi.dinfo_version)); if (copy_to_user(uarg, &ddi, sizeof (ddi))) - return(-EFAULT); + return -EFAULT; break; } @@ -166,13 +166,13 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct digi_info di; if (copy_from_user(&brd, uarg, sizeof(int))) { - return(-EFAULT); + return -EFAULT; } DPR_MGMT(("DIGI_GETBD asking about board: %d\n", brd)); if ((brd < 0) || (brd > dgnc_NumBoards) || (dgnc_NumBoards == 0)) - return (-ENODEV); + return -ENODEV; memset(&di, 0, sizeof(di)); @@ -196,7 +196,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) di.info_bdtype, di.info_bdstate, di.info_nports, di.info_physsize)); if (copy_to_user(uarg, &di, sizeof (di))) - return (-EFAULT); + return -EFAULT; break; } @@ -209,8 +209,8 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) uint board = 0; uint channel = 0; - if (copy_from_user(&ni, uarg, sizeof(struct ni_info))) { - return(-EFAULT); + if (copy_from_user(&ni, uarg, sizeof(ni))) { + return -EFAULT; } DPR_MGMT(("DIGI_GETBD asking about board: %d channel: %d\n", @@ -221,16 +221,16 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* Verify boundaries on board */ if ((board < 0) || (board > dgnc_NumBoards) || (dgnc_NumBoards == 0)) - return (-ENODEV); + return -ENODEV; /* Verify boundaries on channel */ if ((channel < 0) || (channel > dgnc_Board[board]->nasync)) - return (-ENODEV); + return -ENODEV; ch = dgnc_Board[board]->channels[channel]; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (-ENODEV); + return -ENODEV; memset(&ni, 0, sizeof(ni)); ni.board = board; @@ -291,7 +291,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) DGNC_UNLOCK(ch->ch_lock, lock_flags); if (copy_to_user(uarg, &ni, sizeof(ni))) - return (-EFAULT); + return -EFAULT; break; } diff --git a/drivers/staging/dgnc/dgnc_neo.c b/drivers/staging/dgnc/dgnc_neo.c index 8b9e09a83f75..0e2a5e144cfe 100644 --- a/drivers/staging/dgnc/dgnc_neo.c +++ b/drivers/staging/dgnc/dgnc_neo.c @@ -43,8 +43,8 @@ #include "dgnc_tty.h" #include "dgnc_trace.h" -static inline void neo_parse_lsr(struct board_t *brd, uint port); -static inline void neo_parse_isr(struct board_t *brd, uint port); +static inline void neo_parse_lsr(struct dgnc_board *brd, uint port); +static inline void neo_parse_isr(struct dgnc_board *brd, uint port); static void neo_copy_data_from_uart_to_queue(struct channel_t *ch); static inline void neo_clear_break(struct channel_t *ch, int force); static inline void neo_set_cts_flow_control(struct channel_t *ch); @@ -56,7 +56,7 @@ static inline void neo_set_no_input_flow_control(struct channel_t *ch); static inline void neo_set_new_start_stop_chars(struct channel_t *ch); static void neo_parse_modem(struct channel_t *ch, uchar signals); static void neo_tasklet(unsigned long data); -static void neo_vpd(struct board_t *brd); +static void neo_vpd(struct dgnc_board *brd); static void neo_uart_init(struct channel_t *ch); static void neo_uart_off(struct channel_t *ch); static int neo_drain(struct tty_struct *tty, uint seconds); @@ -107,7 +107,7 @@ static uint dgnc_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0 * In this case, we are reading the DVID (Read-only Device Identification) * value of the Neo card. */ -static inline void neo_pci_posting_flush(struct board_t *bd) +static inline void neo_pci_posting_flush(struct dgnc_board *bd) { readb(bd->re_map_membase + 0x8D); } @@ -411,7 +411,7 @@ static inline void neo_clear_break(struct channel_t *ch, int force) /* * Parse the ISR register. */ -static inline void neo_parse_isr(struct board_t *brd, uint port) +static inline void neo_parse_isr(struct dgnc_board *brd, uint port) { struct channel_t *ch; uchar isr; @@ -538,7 +538,7 @@ static inline void neo_parse_isr(struct board_t *brd, uint port) } -static inline void neo_parse_lsr(struct board_t *brd, uint port) +static inline void neo_parse_lsr(struct dgnc_board *brd, uint port) { struct channel_t *ch; int linestatus; @@ -650,7 +650,7 @@ static void neo_param(struct tty_struct *tty) uchar uart_ier = 0; uint baud = 9600; int quot = 0; - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; @@ -911,7 +911,7 @@ static void neo_param(struct tty_struct *tty) */ static void neo_tasklet(unsigned long data) { - struct board_t *bd = (struct board_t *) data; + struct dgnc_board *bd = (struct dgnc_board *) data; struct channel_t *ch; ulong lock_flags; int i; @@ -994,7 +994,7 @@ static void neo_tasklet(unsigned long data) */ static irqreturn_t neo_intr(int irq, void *voidbrd) { - struct board_t *brd = (struct board_t *) voidbrd; + struct dgnc_board *brd = (struct dgnc_board *) voidbrd; struct channel_t *ch; int port = 0; int type = 0; @@ -1111,7 +1111,7 @@ static irqreturn_t neo_intr(int irq, void *voidbrd) * Why would I check EVERY possibility of type of * interrupt, when we know its TXRDY??? * Becuz for some reason, even tho we got triggered for TXRDY, - * it seems to be occassionally wrong. Instead of TX, which + * it seems to be occasionally wrong. Instead of TX, which * it should be, I was getting things like RXDY too. Weird. */ neo_parse_isr(brd, port); @@ -1404,17 +1404,17 @@ static int neo_drain(struct tty_struct *tty, uint seconds) int rc = 0; if (!tty || tty->magic != TTY_MAGIC) { - return (-ENXIO); + return -ENXIO; } un = (struct un_t *) tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) { - return (-ENXIO); + return -ENXIO; } ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) { - return (-ENXIO); + return -ENXIO; } DPR_IOCTL(("%d Drain wait started.\n", __LINE__)); @@ -1439,7 +1439,7 @@ static int neo_drain(struct tty_struct *tty, uint seconds) DPR_IOCTL(("%d Drain wait finished.\n", __LINE__)); } - return (rc); + return rc; } @@ -1939,7 +1939,7 @@ static unsigned int neo_read_eeprom(unsigned char __iomem *base, unsigned int ad } -static void neo_vpd(struct board_t *brd) +static void neo_vpd(struct dgnc_board *brd) { unsigned int i = 0; unsigned int a; diff --git a/drivers/staging/dgnc/dgnc_neo.h b/drivers/staging/dgnc/dgnc_neo.h index 7ec5710a4340..1a4abb128693 100644 --- a/drivers/staging/dgnc/dgnc_neo.h +++ b/drivers/staging/dgnc/dgnc_neo.h @@ -47,7 +47,7 @@ struct neo_uart_struct { u8 fctr; /* WR FCTR - Feature Control Reg */ u8 efr; /* WR EFR - Enhanced Function Reg */ u8 tfifo; /* WR TXCNT/TXTRG - Transmit FIFO Reg */ - u8 rfifo; /* WR RXCNT/RXTRG - Recieve FIFO Reg */ + u8 rfifo; /* WR RXCNT/RXTRG - Receive FIFO Reg */ u8 xoffchar1; /* WR XOFF 1 - XOff Character 1 Reg */ u8 xoffchar2; /* WR XOFF 2 - XOff Character 2 Reg */ u8 xonchar1; /* WR XON 1 - Xon Character 1 Reg */ diff --git a/drivers/staging/dgnc/dgnc_sysfs.c b/drivers/staging/dgnc/dgnc_sysfs.c index 0ea6c8002805..946230c23487 100644 --- a/drivers/staging/dgnc/dgnc_sysfs.c +++ b/drivers/staging/dgnc/dgnc_sysfs.c @@ -152,19 +152,19 @@ void dgnc_remove_driver_sysfiles(struct pci_driver *dgnc_driver) #define DGNC_VERIFY_BOARD(p, bd) \ if (!p) \ - return (0); \ + return 0; \ \ bd = dev_get_drvdata(p); \ if (!bd || bd->magic != DGNC_BOARD_MAGIC) \ - return (0); \ + return 0; \ if (bd->state != BOARD_READY) \ - return (0); \ + return 0; \ static ssize_t dgnc_vpd_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -184,7 +184,7 @@ static DEVICE_ATTR(vpd, S_IRUSR, dgnc_vpd_show, NULL); static ssize_t dgnc_serial_number_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; DGNC_VERIFY_BOARD(p, bd); @@ -201,7 +201,7 @@ static DEVICE_ATTR(serial_number, S_IRUSR, dgnc_serial_number_show, NULL); static ssize_t dgnc_ports_state_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -219,7 +219,7 @@ static DEVICE_ATTR(ports_state, S_IRUSR, dgnc_ports_state_show, NULL); static ssize_t dgnc_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -236,7 +236,7 @@ static DEVICE_ATTR(ports_baud, S_IRUSR, dgnc_ports_baud_show, NULL); static ssize_t dgnc_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -264,7 +264,7 @@ static DEVICE_ATTR(ports_msignals, S_IRUSR, dgnc_ports_msignals_show, NULL); static ssize_t dgnc_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -281,7 +281,7 @@ static DEVICE_ATTR(ports_iflag, S_IRUSR, dgnc_ports_iflag_show, NULL); static ssize_t dgnc_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -298,7 +298,7 @@ static DEVICE_ATTR(ports_cflag, S_IRUSR, dgnc_ports_cflag_show, NULL); static ssize_t dgnc_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -315,7 +315,7 @@ static DEVICE_ATTR(ports_oflag, S_IRUSR, dgnc_ports_oflag_show, NULL); static ssize_t dgnc_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -332,7 +332,7 @@ static DEVICE_ATTR(ports_lflag, S_IRUSR, dgnc_ports_lflag_show, NULL); static ssize_t dgnc_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -349,7 +349,7 @@ static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgnc_ports_digi_flag_show, NULL); static ssize_t dgnc_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -366,7 +366,7 @@ static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgnc_ports_rxcount_show, NULL); static ssize_t dgnc_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; int count = 0; int i = 0; @@ -384,7 +384,7 @@ static DEVICE_ATTR(ports_txcount, S_IRUSR, dgnc_ports_txcount_show, NULL); /* this function creates the sys files that will export each signal status * to sysfs each value will be put in a separate filename */ -void dgnc_create_ports_sysfiles(struct board_t *bd) +void dgnc_create_ports_sysfiles(struct dgnc_board *bd) { int rc = 0; @@ -408,7 +408,7 @@ void dgnc_create_ports_sysfiles(struct board_t *bd) /* removes all the sys files created for that port */ -void dgnc_remove_ports_sysfiles(struct board_t *bd) +void dgnc_remove_ports_sysfiles(struct dgnc_board *bd) { device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud); @@ -427,23 +427,23 @@ void dgnc_remove_ports_sysfiles(struct board_t *bd) static ssize_t dgnc_tty_state_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed"); } @@ -452,23 +452,23 @@ static DEVICE_ATTR(state, S_IRUSR, dgnc_tty_state_show, NULL); static ssize_t dgnc_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_old_baud); } @@ -477,23 +477,23 @@ static DEVICE_ATTR(baud, S_IRUSR, dgnc_tty_baud_show, NULL); static ssize_t dgnc_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; if (ch->ch_open_count) { return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n", @@ -511,23 +511,23 @@ static DEVICE_ATTR(msignals, S_IRUSR, dgnc_tty_msignals_show, NULL); static ssize_t dgnc_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag); } @@ -536,23 +536,23 @@ static DEVICE_ATTR(iflag, S_IRUSR, dgnc_tty_iflag_show, NULL); static ssize_t dgnc_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag); } @@ -561,23 +561,23 @@ static DEVICE_ATTR(cflag, S_IRUSR, dgnc_tty_cflag_show, NULL); static ssize_t dgnc_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag); } @@ -586,23 +586,23 @@ static DEVICE_ATTR(oflag, S_IRUSR, dgnc_tty_oflag_show, NULL); static ssize_t dgnc_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag); } @@ -611,23 +611,23 @@ static DEVICE_ATTR(lflag, S_IRUSR, dgnc_tty_lflag_show, NULL); static ssize_t dgnc_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags); } @@ -636,23 +636,23 @@ static DEVICE_ATTR(digi_flag, S_IRUSR, dgnc_tty_digi_flag_show, NULL); static ssize_t dgnc_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount); } @@ -661,23 +661,23 @@ static DEVICE_ATTR(rxcount, S_IRUSR, dgnc_tty_rxcount_show, NULL); static ssize_t dgnc_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount); } @@ -686,23 +686,23 @@ static DEVICE_ATTR(txcount, S_IRUSR, dgnc_tty_txcount_show, NULL); static ssize_t dgnc_tty_name_show(struct device *d, struct device_attribute *attr, char *buf) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; if (!d) - return (0); - un = (struct un_t *) dev_get_drvdata(d); + return 0; + un = dev_get_drvdata(d); if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (0); + return 0; if (bd->state != BOARD_READY) - return (0); + return 0; return snprintf(buf, PAGE_SIZE, "%sn%d%c\n", (un->un_type == DGNC_PRINT) ? "pr" : "tty", diff --git a/drivers/staging/dgnc/dgnc_sysfs.h b/drivers/staging/dgnc/dgnc_sysfs.h index 4b87ce1cc7a2..68c0de5898a4 100644 --- a/drivers/staging/dgnc/dgnc_sysfs.h +++ b/drivers/staging/dgnc/dgnc_sysfs.h @@ -26,14 +26,14 @@ #include <linux/device.h> -struct board_t; +struct dgnc_board; struct channel_t; struct un_t; struct pci_driver; struct class_device; -extern void dgnc_create_ports_sysfiles(struct board_t *bd); -extern void dgnc_remove_ports_sysfiles(struct board_t *bd); +extern void dgnc_create_ports_sysfiles(struct dgnc_board *bd); +extern void dgnc_remove_ports_sysfiles(struct dgnc_board *bd); extern void dgnc_create_driver_sysfiles(struct pci_driver *); extern void dgnc_remove_driver_sysfiles(struct pci_driver *); diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index a7bb6bceb9e7..a6c6aba82d72 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -38,7 +38,6 @@ */ #include <linux/kernel.h> -#include <linux/version.h> #include <linux/sched.h> /* For jiffies, task states */ #include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */ #include <linux/module.h> @@ -60,16 +59,14 @@ #include "dpacompat.h" #include "dgnc_sysfs.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) #define init_MUTEX(sem) sema_init(sem, 1) #define DECLARE_MUTEX(name) \ struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) -#endif /* * internal variables */ -static struct board_t *dgnc_BoardsByMajor[256]; +static struct dgnc_board *dgnc_BoardsByMajor[256]; static uchar *dgnc_TmpWriteBuf = NULL; static DECLARE_MUTEX(dgnc_TmpWriteSem); @@ -126,13 +123,8 @@ static void dgnc_tty_flush_buffer(struct tty_struct *tty); static void dgnc_tty_hangup(struct tty_struct *tty); static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value); static int dgnc_get_modem_info(struct channel_t *ch, unsigned int __user *value); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) static int dgnc_tty_tiocmget(struct tty_struct *tty); static int dgnc_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -#else -static int dgnc_tty_tiocmget(struct tty_struct *tty, struct file *file); -static int dgnc_tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); -#endif static int dgnc_tty_send_break(struct tty_struct *tty, int msec); static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout); static int dgnc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count); @@ -190,10 +182,10 @@ int dgnc_tty_preinit(void) if (!dgnc_TmpWriteBuf) { DPR_INIT(("unable to allocate tmp write buf")); - return (-ENOMEM); + return -ENOMEM; } - return(0); + return 0; } @@ -202,14 +194,14 @@ int dgnc_tty_preinit(void) * * Init the tty subsystem for this board. */ -int dgnc_tty_register(struct board_t *brd) +int dgnc_tty_register(struct dgnc_board *brd) { int rc = 0; DPR_INIT(("tty_register start\n")); - memset(&brd->SerialDriver, 0, sizeof(struct tty_driver)); - memset(&brd->PrintDriver, 0, sizeof(struct tty_driver)); + memset(&brd->SerialDriver, 0, sizeof(brd->SerialDriver)); + memset(&brd->PrintDriver, 0, sizeof(brd->PrintDriver)); brd->SerialDriver.magic = TTY_DRIVER_MAGIC; @@ -230,25 +222,15 @@ int dgnc_tty_register(struct board_t *brd) * The kernel wants space to store pointers to * tty_struct's and termios's. */ - brd->SerialDriver.ttys = kzalloc(brd->maxports * sizeof(struct tty_struct *), GFP_KERNEL); + brd->SerialDriver.ttys = kzalloc(brd->maxports * sizeof(*brd->SerialDriver.ttys), GFP_KERNEL); if (!brd->SerialDriver.ttys) - return(-ENOMEM); + return -ENOMEM; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - brd->SerialDriver.refcount = brd->TtyRefCnt; -#else kref_init(&brd->SerialDriver.kref); -#endif - - brd->SerialDriver.termios = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL); + brd->SerialDriver.termios = kzalloc(brd->maxports * sizeof(*brd->SerialDriver.termios), GFP_KERNEL); if (!brd->SerialDriver.termios) - return(-ENOMEM); + return -ENOMEM; -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) - brd->SerialDriver.termios_locked = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL); - if (!brd->SerialDriver.termios_locked) - return(-ENOMEM); -#endif /* * Entry points for driver. Called by the kernel from * tty_io.c and n_tty.c. @@ -260,14 +242,14 @@ int dgnc_tty_register(struct board_t *brd) rc = tty_register_driver(&brd->SerialDriver); if (rc < 0) { APR(("Can't register tty device (%d)\n", rc)); - return(rc); + return rc; } brd->dgnc_Major_Serial_Registered = TRUE; } /* * If we're doing transparent print, we have to do all of the above - * again, seperately so we don't get the LD confused about what major + * again, separately so we don't get the LD confused about what major * we are when we get into the dgnc_tty_open() routine. */ brd->PrintDriver.magic = TTY_DRIVER_MAGIC; @@ -286,28 +268,16 @@ int dgnc_tty_register(struct board_t *brd) /* * The kernel wants space to store pointers to - * tty_struct's and termios's. Must be seperate from + * tty_struct's and termios's. Must be separated from * the Serial Driver so we don't get confused */ - brd->PrintDriver.ttys = kzalloc(brd->maxports * sizeof(struct tty_struct *), GFP_KERNEL); + brd->PrintDriver.ttys = kzalloc(brd->maxports * sizeof(*brd->PrintDriver.ttys), GFP_KERNEL); if (!brd->PrintDriver.ttys) - return(-ENOMEM); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - brd->PrintDriver.refcount = brd->TtyRefCnt; -#else + return -ENOMEM; kref_init(&brd->PrintDriver.kref); -#endif - - brd->PrintDriver.termios = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL); + brd->PrintDriver.termios = kzalloc(brd->maxports * sizeof(*brd->PrintDriver.termios), GFP_KERNEL); if (!brd->PrintDriver.termios) - return(-ENOMEM); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) - brd->PrintDriver.termios_locked = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL); - if (!brd->PrintDriver.termios_locked) - return(-ENOMEM); -#endif + return -ENOMEM; /* * Entry points for driver. Called by the kernel from @@ -320,7 +290,7 @@ int dgnc_tty_register(struct board_t *brd) rc = tty_register_driver(&brd->PrintDriver); if (rc < 0) { APR(("Can't register Transparent Print device (%d)\n", rc)); - return(rc); + return rc; } brd->dgnc_Major_TransparentPrint_Registered = TRUE; } @@ -331,7 +301,7 @@ int dgnc_tty_register(struct board_t *brd) DPR_INIT(("DGNC REGISTER TTY: MAJOR: %d\n", brd->SerialDriver.major)); - return (rc); + return rc; } @@ -341,14 +311,14 @@ int dgnc_tty_register(struct board_t *brd) * Init the tty subsystem. Called once per board after board has been * downloaded and init'ed. */ -int dgnc_tty_init(struct board_t *brd) +int dgnc_tty_init(struct dgnc_board *brd) { int i; void __iomem *vaddr; struct channel_t *ch; if (!brd) - return (-ENXIO); + return -ENXIO; DPR_INIT(("dgnc_tty_init start\n")); @@ -371,7 +341,7 @@ int dgnc_tty_init(struct board_t *brd) * Okay to malloc with GFP_KERNEL, we are not at * interrupt context, and there are no locks held. */ - brd->channels[i] = kzalloc(sizeof(struct channel_t), GFP_KERNEL); + brd->channels[i] = kzalloc(sizeof(*brd->channels[i]), GFP_KERNEL); if (!brd->channels[i]) { DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n", __FILE__, __LINE__)); @@ -436,7 +406,7 @@ int dgnc_tty_init(struct board_t *brd) DPR_INIT(("dgnc_tty_init finish\n")); - return (0); + return 0; } @@ -460,7 +430,7 @@ void dgnc_tty_post_uninit(void) * Uninitialize the TTY portion of this driver. Free all memory and * resources. */ -void dgnc_tty_uninit(struct board_t *brd) +void dgnc_tty_uninit(struct dgnc_board *brd) { int i = 0; @@ -550,7 +520,7 @@ void dgnc_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int /* * Loop while data remains. */ - while (nbuf > 0 && ch->ch_sniff_buf != 0) { + while (nbuf > 0 && ch->ch_sniff_buf) { /* * Determine the amount of available space left in the * buffer. If there's none, wait until some appears. @@ -671,7 +641,7 @@ static void dgnc_wmove(struct channel_t *ch, char *buf, uint n) *=======================================================================*/ void dgnc_input(struct channel_t *ch) { - struct board_t *bd; + struct dgnc_board *bd; struct tty_struct *tp; struct tty_ldisc *ld; uint rmask; @@ -867,7 +837,7 @@ void dgnc_input(struct channel_t *ch) ************************************************************************/ void dgnc_carrier(struct channel_t *ch) { - struct board_t *bd; + struct dgnc_board *bd; int virt_carrier = 0; int phys_carrier = 0; @@ -1158,7 +1128,6 @@ void dgnc_wakeup_writes(struct channel_t *ch) } if (ch->ch_tun.un_flags & UN_ISOPEN) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && ch->ch_tun.un_tty->ldisc->ops->write_wakeup) { @@ -1166,15 +1135,6 @@ void dgnc_wakeup_writes(struct channel_t *ch) (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty); DGNC_LOCK(ch->ch_lock, lock_flags); } -#else - if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - ch->ch_tun.un_tty->ldisc.ops->write_wakeup) - { - DGNC_UNLOCK(ch->ch_lock, lock_flags); - (ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty); - DGNC_LOCK(ch->ch_lock, lock_flags); - } -#endif wake_up_interruptible(&ch->ch_tun.un_tty->write_wait); @@ -1210,7 +1170,6 @@ void dgnc_wakeup_writes(struct channel_t *ch) } if (ch->ch_pun.un_flags & UN_ISOPEN) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && ch->ch_pun.un_tty->ldisc->ops->write_wakeup) { @@ -1218,15 +1177,6 @@ void dgnc_wakeup_writes(struct channel_t *ch) (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty); DGNC_LOCK(ch->ch_lock, lock_flags); } -#else - if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - ch->ch_pun.un_tty->ldisc.ops->write_wakeup) - { - DGNC_UNLOCK(ch->ch_lock, lock_flags); - (ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty); - DGNC_LOCK(ch->ch_lock, lock_flags); - } -#endif wake_up_interruptible(&ch->ch_pun.un_tty->write_wait); @@ -1260,7 +1210,7 @@ void dgnc_wakeup_writes(struct channel_t *ch) */ static int dgnc_tty_open(struct tty_struct *tty, struct file *file) { - struct board_t *brd; + struct dgnc_board *brd; struct channel_t *ch; struct un_t *un; uint major = 0; @@ -1473,7 +1423,7 @@ static int dgnc_tty_open(struct tty_struct *tty, struct file *file) DGNC_UNLOCK(ch->ch_lock, lock_flags); DPR_OPEN(("dgnc_tty_open finished\n")); - return (rc); + return rc; } @@ -1491,12 +1441,12 @@ static int dgnc_block_til_ready(struct tty_struct *tty, struct file *file, struc int sleep_on_un_flags = 0; if (!tty || tty->magic != TTY_MAGIC || !file || !ch || ch->magic != DGNC_CHANNEL_MAGIC) { - return (-ENXIO); + return -ENXIO; } un = tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) { - return (-ENXIO); + return -ENXIO; } DPR_OPEN(("dgnc_block_til_ready - before block.\n")); @@ -1624,12 +1574,12 @@ static int dgnc_block_til_ready(struct tty_struct *tty, struct file *file, struc if (retval) { DPR_OPEN(("dgnc_block_til_ready - done. error. retval: %x\n", retval)); - return(retval); + return retval; } DPR_OPEN(("dgnc_block_til_ready - done no error. jiffies: %lu\n", jiffies)); - return(0); + return 0; } @@ -1667,7 +1617,7 @@ static void dgnc_tty_hangup(struct tty_struct *tty) static void dgnc_tty_close(struct tty_struct *tty, struct file *file) { struct ktermios *ts; - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; ulong lock_flags; @@ -1843,15 +1793,15 @@ static int dgnc_tty_chars_in_buffer(struct tty_struct *tty) ulong lock_flags = 0; if (tty == NULL) - return(0); + return 0; un = tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; DGNC_LOCK(ch->ch_lock, lock_flags); @@ -1873,7 +1823,7 @@ static int dgnc_tty_chars_in_buffer(struct tty_struct *tty) DPR_WRITE(("dgnc_tty_chars_in_buffer. Port: %x - %d (head: %d tail: %d)\n", ch->ch_portnum, chars, thead, ttail)); - return(chars); + return chars; } @@ -1891,22 +1841,22 @@ static int dgnc_maxcps_room(struct tty_struct *tty, int bytes_available) struct un_t *un = NULL; if (!tty) - return (bytes_available); + return bytes_available; un = tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) - return (bytes_available); + return bytes_available; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (bytes_available); + return bytes_available; /* * If its not the Transparent print device, return * the full data amount. */ if (un->un_type != DGNC_PRINT) - return (bytes_available); + return bytes_available; if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0 ) { int cps_limit = 0; @@ -1931,7 +1881,7 @@ static int dgnc_maxcps_room(struct tty_struct *tty, int bytes_available) bytes_available = min(cps_limit, bytes_available); } - return (bytes_available); + return bytes_available; } @@ -1951,15 +1901,15 @@ static int dgnc_tty_write_room(struct tty_struct *tty) ulong lock_flags = 0; if (tty == NULL || dgnc_TmpWriteBuf == NULL) - return(0); + return 0; un = tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) - return (0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (0); + return 0; DGNC_LOCK(ch->ch_lock, lock_flags); @@ -1994,7 +1944,7 @@ static int dgnc_tty_write_room(struct tty_struct *tty) DPR_WRITE(("dgnc_tty_write_room - %d tail: %d head: %d\n", ret, tail, head)); - return(ret); + return ret; } @@ -2037,18 +1987,18 @@ static int dgnc_tty_write(struct tty_struct *tty, int from_user = 0; if (tty == NULL || dgnc_TmpWriteBuf == NULL) - return(0); + return 0; un = tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) - return(0); + return 0; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return(0); + return 0; if (!count) - return(0); + return 0; DPR_WRITE(("dgnc_tty_write: Port: %x tty=%p user=%d len=%d\n", ch->ch_portnum, tty, from_user, count)); @@ -2090,7 +2040,7 @@ static int dgnc_tty_write(struct tty_struct *tty, */ if (count <= 0) { DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(0); + return 0; } /* @@ -2120,7 +2070,7 @@ static int dgnc_tty_write(struct tty_struct *tty, */ if (count <= 0) { DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(0); + return 0; } if (from_user) { @@ -2136,7 +2086,7 @@ static int dgnc_tty_write(struct tty_struct *tty, */ /* we're allowed to block if it's from_user */ if (down_interruptible(&dgnc_TmpWriteSem)) { - return (-EINTR); + return -EINTR; } /* @@ -2147,7 +2097,7 @@ static int dgnc_tty_write(struct tty_struct *tty, if (!count) { up(&dgnc_TmpWriteSem); - return(-EFAULT); + return -EFAULT; } DGNC_LOCK(ch->ch_lock, lock_flags); @@ -2229,18 +2179,15 @@ static int dgnc_tty_write(struct tty_struct *tty, ch->ch_bd->bd_ops->copy_data_from_queue_to_uart(ch); } - return (count); + return count; } /* * Return modem signals to ld. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) + static int dgnc_tty_tiocmget(struct tty_struct *tty) -#else -static int dgnc_tty_tiocmget(struct tty_struct *tty, struct file *file) -#endif { struct channel_t *ch; struct un_t *un; @@ -2293,15 +2240,11 @@ static int dgnc_tty_tiocmget(struct tty_struct *tty, struct file *file) * * Set modem signals, called by ld. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) + static int dgnc_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) -#else -static int dgnc_tty_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -#endif { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; int ret = -EIO; @@ -2349,7 +2292,7 @@ static int dgnc_tty_tiocmset(struct tty_struct *tty, struct file *file, DPR_IOCTL(("dgnc_tty_tiocmset finish\n")); - return (0); + return 0; } @@ -2360,7 +2303,7 @@ static int dgnc_tty_tiocmset(struct tty_struct *tty, struct file *file, */ static int dgnc_tty_send_break(struct tty_struct *tty, int msec) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; int ret = -EIO; @@ -2402,7 +2345,7 @@ static int dgnc_tty_send_break(struct tty_struct *tty, int msec) DPR_IOCTL(("dgnc_tty_send_break finish\n")); - return (0); + return 0; } @@ -2414,7 +2357,7 @@ static int dgnc_tty_send_break(struct tty_struct *tty, int msec) */ static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; int rc; @@ -2450,7 +2393,7 @@ static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout) */ static void dgnc_tty_send_xchar(struct tty_struct *tty, char c) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; ulong lock_flags; @@ -2497,7 +2440,7 @@ static inline int dgnc_get_mstat(struct channel_t *ch) DPR_IOCTL(("dgnc_getmstat start\n")); if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return(-ENXIO); + return -ENXIO; DGNC_LOCK(ch->ch_lock, lock_flags); @@ -2522,7 +2465,7 @@ static inline int dgnc_get_mstat(struct channel_t *ch) DPR_IOCTL(("dgnc_getmstat finish\n")); - return(result); + return result; } @@ -2538,17 +2481,17 @@ static int dgnc_get_modem_info(struct channel_t *ch, unsigned int __user *value DPR_IOCTL(("dgnc_get_modem_info start\n")); if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return(-ENXIO); + return -ENXIO; result = dgnc_get_mstat(ch); if (result < 0) - return (-ENXIO); + return -ENXIO; rc = put_user(result, value); DPR_IOCTL(("dgnc_get_modem_info finish\n")); - return(rc); + return rc; } @@ -2559,7 +2502,7 @@ static int dgnc_get_modem_info(struct channel_t *ch, unsigned int __user *value */ static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; int ret = -ENXIO; @@ -2587,7 +2530,7 @@ static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, uns ret = get_user(arg, value); if (ret) - return(ret); + return ret; switch (command) { case TIOCMBIS: @@ -2631,7 +2574,7 @@ static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, uns break; default: - return(-EINVAL); + return -EINVAL; } DGNC_LOCK(ch->ch_lock, lock_flags); @@ -2642,7 +2585,7 @@ static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, uns DPR_IOCTL(("dgnc_set_modem_info finish\n")); - return (0); + return 0; } @@ -2662,18 +2605,18 @@ static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retin ulong lock_flags; if (!retinfo) - return (-EFAULT); + return -EFAULT; if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); + return -EFAULT; un = tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) - return (-EFAULT); + return -EFAULT; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (-EFAULT); + return -EFAULT; memset(&tmp, 0, sizeof(tmp)); @@ -2682,9 +2625,9 @@ static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retin DGNC_UNLOCK(ch->ch_lock, lock_flags); if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return (-EFAULT); + return -EFAULT; - return (0); + return 0; } @@ -2698,7 +2641,7 @@ static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retin */ static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; struct digi_t new_digi; @@ -2707,23 +2650,23 @@ static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_i DPR_IOCTL(("DIGI_SETA start\n")); if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); + return -EFAULT; un = tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) - return (-EFAULT); + return -EFAULT; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (-EFAULT); + return -EFAULT; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (-EFAULT); + return -EFAULT; - if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) { + if (copy_from_user(&new_digi, new_info, sizeof(new_digi))) { DPR_IOCTL(("DIGI_SETA failed copy_from_user\n")); - return(-EFAULT); + return -EFAULT; } DGNC_LOCK(ch->ch_lock, lock_flags); @@ -2744,7 +2687,7 @@ static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_i if ((ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) && !(new_digi.digi_flags & DIGI_DTR_TOGGLE)) ch->ch_mostat |= (UART_MCR_DTR); - memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t)); + memcpy(&ch->ch_digi, &new_digi, sizeof(new_digi)); if (ch->ch_digi.digi_maxcps < 1) ch->ch_digi.digi_maxcps = 1; @@ -2773,7 +2716,7 @@ static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_i DPR_IOCTL(("DIGI_SETA finish\n")); - return(0); + return 0; } @@ -2782,7 +2725,7 @@ static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_i */ static void dgnc_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; unsigned long lock_flags; @@ -2878,7 +2821,7 @@ static void dgnc_tty_unthrottle(struct tty_struct *tty) static void dgnc_tty_start(struct tty_struct *tty) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; ulong lock_flags; @@ -2912,7 +2855,7 @@ static void dgnc_tty_start(struct tty_struct *tty) static void dgnc_tty_stop(struct tty_struct *tty) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; ulong lock_flags; @@ -2959,7 +2902,7 @@ static void dgnc_tty_stop(struct tty_struct *tty) */ static void dgnc_tty_flush_chars(struct tty_struct *tty) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; ulong lock_flags; @@ -3056,7 +2999,7 @@ static void dgnc_tty_flush_buffer(struct tty_struct *tty) static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { - struct board_t *bd; + struct dgnc_board *bd; struct channel_t *ch; struct un_t *un; int rc; @@ -3064,19 +3007,19 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, void __user *uarg = (void __user *) arg; if (!tty || tty->magic != TTY_MAGIC) - return (-ENODEV); + return -ENODEV; un = tty->driver_data; if (!un || un->magic != DGNC_UNIT_MAGIC) - return (-ENODEV); + return -ENODEV; ch = un->un_ch; if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) - return (-ENODEV); + return -ENODEV; bd = ch->ch_bd; if (!bd || bd->magic != DGNC_BOARD_MAGIC) - return (-ENODEV); + return -ENODEV; DPR_IOCTL(("dgnc_tty_ioctl start on port %d - cmd %s (%x), arg %lx\n", ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg)); @@ -3086,7 +3029,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, if (un->un_open_count <= 0) { DPR_BASIC(("dgnc_tty_ioctl - unit not open.\n")); DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(-EIO); + return -EIO; } switch (cmd) { @@ -3105,14 +3048,14 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, rc = tty_check_change(tty); DGNC_UNLOCK(ch->ch_lock, lock_flags); if (rc) { - return(rc); + return rc; } rc = ch->ch_bd->bd_ops->drain(tty, 0); if (rc) { DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); + return -EINTR; } DGNC_LOCK(ch->ch_lock, lock_flags); @@ -3126,7 +3069,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg)); - return(0); + return 0; case TCSBRKP: @@ -3138,13 +3081,13 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, rc = tty_check_change(tty); DGNC_UNLOCK(ch->ch_lock, lock_flags); if (rc) { - return(rc); + return rc; } rc = ch->ch_bd->bd_ops->drain(tty, 0); if (rc) { DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); + return -EINTR; } DGNC_LOCK(ch->ch_lock, lock_flags); @@ -3156,19 +3099,19 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg)); - return(0); + return 0; case TIOCSBRK: rc = tty_check_change(tty); DGNC_UNLOCK(ch->ch_lock, lock_flags); if (rc) { - return(rc); + return rc; } rc = ch->ch_bd->bd_ops->drain(tty, 0); if (rc) { DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); + return -EINTR; } DGNC_LOCK(ch->ch_lock, lock_flags); @@ -3180,7 +3123,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg)); - return(0); + return 0; case TIOCCBRK: /* Do Nothing */ @@ -3192,31 +3135,31 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DGNC_UNLOCK(ch->ch_lock, lock_flags); rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg); - return(rc); + return rc; case TIOCSSOFTCAR: DGNC_UNLOCK(ch->ch_lock, lock_flags); rc = get_user(arg, (unsigned long __user *) arg); if (rc) - return(rc); + return rc; DGNC_LOCK(ch->ch_lock, lock_flags); tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); ch->ch_bd->bd_ops->param(tty); DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(0); + return 0; case TIOCMGET: DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(dgnc_get_modem_info(ch, uarg)); + return dgnc_get_modem_info(ch, uarg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(dgnc_set_modem_info(tty, cmd, uarg)); + return dgnc_set_modem_info(tty, cmd, uarg); /* * Here are any additional ioctl's that we want to implement @@ -3235,7 +3178,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, rc = tty_check_change(tty); if (rc) { DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(rc); + return rc; } if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) { @@ -3265,7 +3208,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, /* pretend we didn't recognize this IOCTL */ DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(-ENOIOCTLCMD); + return -ENOIOCTLCMD; case TCSETSF: case TCSETSW: /* @@ -3291,14 +3234,14 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, rc = ch->ch_bd->bd_ops->drain(tty, 0); if (rc) { DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d\n", rc)); - return(-EINTR); + return -EINTR; } DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg)); /* pretend we didn't recognize this */ - return(-ENOIOCTLCMD); + return -ENOIOCTLCMD; case TCSETAW: @@ -3306,21 +3249,21 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, rc = ch->ch_bd->bd_ops->drain(tty, 0); if (rc) { DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); + return -EINTR; } /* pretend we didn't recognize this */ - return(-ENOIOCTLCMD); + return -ENOIOCTLCMD; case TCXONC: DGNC_UNLOCK(ch->ch_lock, lock_flags); /* Make the ld do it */ - return(-ENOIOCTLCMD); + return -ENOIOCTLCMD; case DIGI_GETA: /* get information for ditty */ DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(dgnc_tty_digigeta(tty, uarg)); + return dgnc_tty_digigeta(tty, uarg); case DIGI_SETAW: case DIGI_SETAF: @@ -3332,7 +3275,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, rc = ch->ch_bd->bd_ops->drain(tty, 0); if (rc) { DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); + return -EINTR; } DGNC_LOCK(ch->ch_lock, lock_flags); } @@ -3343,7 +3286,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, case DIGI_SETA: DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(dgnc_tty_digiseta(tty, uarg)); + return dgnc_tty_digiseta(tty, uarg); case DIGI_LOOPBACK: { @@ -3352,7 +3295,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DGNC_UNLOCK(ch->ch_lock, lock_flags); rc = get_user(loopback, (unsigned int __user *) arg); if (rc) - return(rc); + return rc; DGNC_LOCK(ch->ch_lock, lock_flags); /* Enable/disable internal loopback for this port */ @@ -3363,13 +3306,13 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, ch->ch_bd->bd_ops->param(tty); DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(0); + return 0; } case DIGI_GETCUSTOMBAUD: DGNC_UNLOCK(ch->ch_lock, lock_flags); rc = put_user(ch->ch_custom_speed, (unsigned int __user *) arg); - return(rc); + return rc; case DIGI_SETCUSTOMBAUD: { @@ -3378,12 +3321,12 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DGNC_UNLOCK(ch->ch_lock, lock_flags); rc = get_user(new_rate, (unsigned int __user *) arg); if (rc) - return(rc); + return rc; DGNC_LOCK(ch->ch_lock, lock_flags); dgnc_set_custom_speed(ch, new_rate); ch->ch_bd->bd_ops->param(tty); DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(0); + return 0; } /* @@ -3399,11 +3342,11 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DGNC_UNLOCK(ch->ch_lock, lock_flags); rc = get_user(c, (unsigned char __user *) arg); if (rc) - return(rc); + return rc; DGNC_LOCK(ch->ch_lock, lock_flags); ch->ch_bd->bd_ops->send_immediate_char(ch, c); DGNC_UNLOCK(ch->ch_lock, lock_flags); - return(0); + return 0; } /* @@ -3426,10 +3369,10 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DGNC_UNLOCK(ch->ch_lock, lock_flags); - if (copy_to_user(uarg, &buf, sizeof(struct digi_getcounter))) { - return (-EFAULT); + if (copy_to_user(uarg, &buf, sizeof(buf))) { + return -EFAULT; } - return(0); + return 0; } /* @@ -3454,7 +3397,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DGNC_UNLOCK(ch->ch_lock, lock_flags); rc = put_user(events, (unsigned int __user *) arg); - return(rc); + return rc; } /* @@ -3474,8 +3417,8 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, /* * Get data from user first. */ - if (copy_from_user(&buf, uarg, sizeof(struct digi_getbuffer))) { - return (-EFAULT); + if (copy_from_user(&buf, uarg, sizeof(buf))) { + return -EFAULT; } DGNC_LOCK(ch->ch_lock, lock_flags); @@ -3520,10 +3463,10 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DGNC_UNLOCK(ch->ch_lock, lock_flags); - if (copy_to_user(uarg, &buf, sizeof(struct digi_getbuffer))) { - return (-EFAULT); + if (copy_to_user(uarg, &buf, sizeof(buf))) { + return -EFAULT; } - return(0); + return 0; } default: DGNC_UNLOCK(ch->ch_lock, lock_flags); @@ -3532,7 +3475,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DPR_IOCTL(("dgnc_tty_ioctl end - cmd %s (%x), arg %lx\n", dgnc_ioctl_name(cmd), cmd, arg)); - return(-ENOIOCTLCMD); + return -ENOIOCTLCMD; } DGNC_UNLOCK(ch->ch_lock, lock_flags); @@ -3540,5 +3483,5 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, DPR_IOCTL(("dgnc_tty_ioctl end - cmd %s (%x), arg %lx\n", dgnc_ioctl_name(cmd), cmd, arg)); - return(0); + return 0; } diff --git a/drivers/staging/dgnc/dgnc_tty.h b/drivers/staging/dgnc/dgnc_tty.h index deb388d2f4cf..9d1c2847bd94 100644 --- a/drivers/staging/dgnc/dgnc_tty.h +++ b/drivers/staging/dgnc/dgnc_tty.h @@ -24,13 +24,13 @@ #include "dgnc_driver.h" -int dgnc_tty_register(struct board_t *brd); +int dgnc_tty_register(struct dgnc_board *brd); int dgnc_tty_preinit(void); -int dgnc_tty_init(struct board_t *); +int dgnc_tty_init(struct dgnc_board *); void dgnc_tty_post_uninit(void); -void dgnc_tty_uninit(struct board_t *); +void dgnc_tty_uninit(struct dgnc_board *); void dgnc_input(struct channel_t *ch); void dgnc_carrier(struct channel_t *ch); diff --git a/drivers/staging/dgnc/digi.h b/drivers/staging/dgnc/digi.h index eb6e37125727..6a9adf6591eb 100644 --- a/drivers/staging/dgnc/digi.h +++ b/drivers/staging/dgnc/digi.h @@ -201,9 +201,9 @@ struct shrink_buf_struct { unsigned int shrink_buf_vaddr; /* Virtual address of board */ unsigned int shrink_buf_phys; /* Physical address of board */ unsigned int shrink_buf_bseg; /* Amount of board memory */ - unsigned int shrink_buf_hseg; /* '186 Begining of Dual-Port */ + unsigned int shrink_buf_hseg; /* '186 Beginning of Dual-Port */ - unsigned int shrink_buf_lseg; /* '186 Begining of freed memory */ + unsigned int shrink_buf_lseg; /* '186 Beginning of freed memory */ unsigned int shrink_buf_mseg; /* Linear address from start of dual-port were freed memory begins, host viewpoint. */ diff --git a/drivers/staging/dgrp/dgrp_sysfs.c b/drivers/staging/dgrp/dgrp_sysfs.c index 8cee9c8bc38b..9a18a2c9e73b 100644 --- a/drivers/staging/dgrp/dgrp_sysfs.c +++ b/drivers/staging/dgrp/dgrp_sysfs.c @@ -157,7 +157,7 @@ static ssize_t dgrp_node_state_show(struct device *c, if (!c) return 0; - nd = (struct nd_struct *) dev_get_drvdata(c); + nd = dev_get_drvdata(c); if (!nd) return 0; @@ -174,7 +174,7 @@ static ssize_t dgrp_node_description_show(struct device *c, if (!c) return 0; - nd = (struct nd_struct *) dev_get_drvdata(c); + nd = dev_get_drvdata(c); if (!nd) return 0; @@ -192,7 +192,7 @@ static ssize_t dgrp_node_hw_version_show(struct device *c, if (!c) return 0; - nd = (struct nd_struct *) dev_get_drvdata(c); + nd = dev_get_drvdata(c); if (!nd) return 0; @@ -212,7 +212,7 @@ static ssize_t dgrp_node_hw_id_show(struct device *c, if (!c) return 0; - nd = (struct nd_struct *) dev_get_drvdata(c); + nd = dev_get_drvdata(c); if (!nd) return 0; @@ -232,7 +232,7 @@ static ssize_t dgrp_node_sw_version_show(struct device *c, if (!c) return 0; - nd = (struct nd_struct *) dev_get_drvdata(c); + nd = dev_get_drvdata(c); if (!nd) return 0; @@ -311,7 +311,7 @@ static ssize_t dgrp_tty_state_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; @@ -328,7 +328,7 @@ static ssize_t dgrp_tty_baud_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; @@ -348,7 +348,7 @@ static ssize_t dgrp_tty_msignals_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; @@ -377,7 +377,7 @@ static ssize_t dgrp_tty_iflag_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; @@ -396,7 +396,7 @@ static ssize_t dgrp_tty_cflag_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; @@ -415,7 +415,7 @@ static ssize_t dgrp_tty_oflag_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; @@ -434,7 +434,7 @@ static ssize_t dgrp_tty_digi_flag_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; @@ -453,7 +453,7 @@ static ssize_t dgrp_tty_rxcount_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; @@ -472,7 +472,7 @@ static ssize_t dgrp_tty_txcount_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; @@ -493,7 +493,7 @@ static ssize_t dgrp_tty_name_show(struct device *d, if (!d) return 0; - un = (struct un_struct *) dev_get_drvdata(d); + un = dev_get_drvdata(d); if (!un) return 0; ch = un->un_ch; diff --git a/drivers/staging/dwc2/TODO b/drivers/staging/dwc2/TODO new file mode 100644 index 000000000000..282470d55315 --- /dev/null +++ b/drivers/staging/dwc2/TODO @@ -0,0 +1,33 @@ +TODO: + - Dan Carpenter would like to see some cleanups to the microframe + scheduler code: + http://www.mail-archive.com/linux-usb@vger.kernel.org/msg26650.html + + - Should merge the NAK holdoff patch from Raspberry Pi + (http://marc.info/?l=linux-usb&m=137625067103833). But as it stands + that patch is incomplete, it needs more investigation to see if it + can be made to work for non-Raspberry Pi platforms that lack the + special FIQ interrupt that the Pi has. Without this patch, the driver + has a high interrupt rate (8K/sec). + + - The Raspberry Pi platform needs to have support for its FIQ interrupt + added, to get the same level of functionality as the downstream + driver. The raspberrypi.org developers have indicated they are + willing to help with that. + + - Some of the default driver parameters (see 'struct dwc2_core_params' + in core.h) won't work for many platforms. So DT attributes will need + to be added for some of these. But that can be done as-needed as new + platforms are added. + + - Eventually the driver should be merged with the s3c-hsotg peripheral + mode driver, so that both modes of operation can be supported with a + single driver. But I think that can wait till after the driver has + been moved to mainline. + + - After that, OTG support can be added. I'm not sure how much demand + there is for that, though, so I have that as a low priority. + +Please send any patches for this driver to Paul Zimmerman <paulz@synopsys.com> +and Greg Kroah-Hartman <gregkh@linuxfoundation.org>. And please CC linux-usb +<linux-usb@vger.kernel.org> too. diff --git a/drivers/staging/dwc2/core.c b/drivers/staging/dwc2/core.c index 06dae67a9d62..6d001b52f652 100644 --- a/drivers/staging/dwc2/core.c +++ b/drivers/staging/dwc2/core.c @@ -564,7 +564,7 @@ void dwc2_core_host_init(struct dwc2_hsotg *hsotg) /* * This bit allows dynamic reloading of the HFIR register during - * runtime. This bit needs to be programmed during inital configuration + * runtime. This bit needs to be programmed during initial configuration * and its value must not be changed during runtime. */ if (hsotg->core_params->reload_ctl > 0) { @@ -2205,7 +2205,7 @@ int dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val) { #ifndef NO_FS_PHY_HW_CHECKS int valid = 0; - u32 hs_phy_type, fs_phy_type; + u32 hs_phy_type, fs_phy_type; #endif int retval = 0; @@ -2553,7 +2553,7 @@ int dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val) hsotg->core_params->ahbcfg = val; else hsotg->core_params->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << - GAHBCFG_HBSTLEN_SHIFT; + GAHBCFG_HBSTLEN_SHIFT; return 0; } @@ -2736,6 +2736,26 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) return 0; } +int dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val) +{ + int retval = 0; + + if (DWC2_PARAM_TEST(val, 0, 1)) { + if (val >= 0) { + dev_err(hsotg->dev, + "'%d' invalid for parameter uframe_sched\n", + val); + dev_err(hsotg->dev, "uframe_sched must be 0 or 1\n"); + } + val = 1; + dev_dbg(hsotg->dev, "Setting uframe_sched to %d\n", val); + retval = -EINVAL; + } + + hsotg->core_params->uframe_sched = val; + return retval; +} + /* * This function is called during module intialization to pass module parameters * for the DWC_otg core. It returns non-0 if any parameters are invalid. @@ -2782,6 +2802,7 @@ int dwc2_set_parameters(struct dwc2_hsotg *hsotg, retval |= dwc2_set_param_reload_ctl(hsotg, params->reload_ctl); retval |= dwc2_set_param_ahbcfg(hsotg, params->ahbcfg); retval |= dwc2_set_param_otg_ver(hsotg, params->otg_ver); + retval |= dwc2_set_param_uframe_sched(hsotg, params->uframe_sched); return retval; } diff --git a/drivers/staging/dwc2/core.h b/drivers/staging/dwc2/core.h index 9102f66d0111..fab718d9b326 100644 --- a/drivers/staging/dwc2/core.h +++ b/drivers/staging/dwc2/core.h @@ -188,6 +188,7 @@ enum dwc2_lx_state { * bits defined by GAHBCFG_CTRL_MASK are controlled * by the driver and are ignored in this * configuration value. + * @uframe_sched: True to enable the microframe scheduler * * The following parameters may be specified when starting the module. These * parameters define how the DWC_otg controller should be configured. A @@ -224,6 +225,7 @@ struct dwc2_core_params { int ts_dline; int reload_ctl; int ahbcfg; + int uframe_sched; }; /** @@ -292,7 +294,7 @@ struct dwc2_hw_params { unsigned dev_token_q_depth:5; unsigned max_transfer_size:26; unsigned max_packet_count:11; - unsigned host_channels:4; + unsigned host_channels:5; unsigned hs_phy_type:2; unsigned fs_phy_type:2; unsigned i2c_enable:1; @@ -370,6 +372,7 @@ struct dwc2_hw_params { * This value is in microseconds per (micro)frame. The * assumption is that all periodic transfers may occur in * the same (micro)frame. + * @frame_usecs: Internal variable used by the microframe scheduler * @frame_number: Frame number read from the core at SOF. The value ranges * from 0 to HFNUM_MAX_FRNUM. * @periodic_qh_count: Count of periodic QHs, if using several eps. Used for @@ -382,6 +385,8 @@ struct dwc2_hw_params { * host channel is available for non-periodic transactions. * @non_periodic_channels: Number of host channels assigned to non-periodic * transfers + * @available_host_channels Number of host channels available for the microframe + * scheduler to use * @hc_ptr_array: Array of pointers to the host channel descriptors. * Allows accessing a host channel descriptor given the * host channel number. This is useful in interrupt @@ -436,6 +441,7 @@ struct dwc2_hsotg { struct list_head periodic_sched_assigned; struct list_head periodic_sched_queued; u16 periodic_usecs; + u16 frame_usecs[8]; u16 frame_number; u16 periodic_qh_count; @@ -451,6 +457,7 @@ struct dwc2_hsotg { struct list_head free_hc_list; int periodic_channels; int non_periodic_channels; + int available_host_channels; struct dwc2_host_chan *hc_ptr_array[MAX_EPS_CHANNELS]; u8 *status_buf; dma_addr_t status_buf_dma; diff --git a/drivers/staging/dwc2/hcd.c b/drivers/staging/dwc2/hcd.c index da0d35cc33ce..83629d84155d 100644 --- a/drivers/staging/dwc2/hcd.c +++ b/drivers/staging/dwc2/hcd.c @@ -537,10 +537,15 @@ static void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg) int i; hsotg->flags.d32 = 0; - hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active; - hsotg->non_periodic_channels = 0; - hsotg->periodic_channels = 0; + + if (hsotg->core_params->uframe_sched > 0) { + hsotg->available_host_channels = + hsotg->core_params->host_channels; + } else { + hsotg->non_periodic_channels = 0; + hsotg->periodic_channels = 0; + } /* * Put all channels in the free channel list and clean up channel @@ -716,8 +721,7 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, * @qh: Transactions from the first QTD for this QH are selected and assigned * to a free host channel */ -static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, - struct dwc2_qh *qh) +static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { struct dwc2_host_chan *chan; struct dwc2_hcd_urb *urb; @@ -729,18 +733,18 @@ static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, if (list_empty(&qh->qtd_list)) { dev_dbg(hsotg->dev, "No QTDs in QH list\n"); - return; + return -ENOMEM; } if (list_empty(&hsotg->free_hc_list)) { dev_dbg(hsotg->dev, "No free channel to assign\n"); - return; + return -ENOMEM; } chan = list_first_entry(&hsotg->free_hc_list, struct dwc2_host_chan, hc_list_entry); - /* Remove the host channel from the free list */ + /* Remove host channel from free list */ list_del_init(&chan->hc_list_entry); qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry); @@ -780,6 +784,10 @@ static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, chan->data_pid_start = qh->data_toggle; chan->multi_count = 1; + if ((urb->actual_length < 0 || urb->actual_length > urb->length) && + !dwc2_hcd_is_pipe_in(&urb->pipe_info)) + urb->actual_length = urb->length; + if (hsotg->core_params->dma_enable > 0) { chan->xfer_dma = urb->dma + urb->actual_length; @@ -817,7 +825,7 @@ static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, &hsotg->free_hc_list); qtd->in_process = 0; qh->channel = NULL; - return; + return -ENOMEM; } } else { chan->align_buf = 0; @@ -836,6 +844,8 @@ static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, dwc2_hc_init(hsotg, chan); chan->qh = qh; + + return 0; } /** @@ -864,8 +874,14 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( while (qh_ptr != &hsotg->periodic_sched_ready) { if (list_empty(&hsotg->free_hc_list)) break; + if (hsotg->core_params->uframe_sched > 0) { + if (hsotg->available_host_channels <= 1) + break; + hsotg->available_host_channels--; + } qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); - dwc2_assign_and_init_hc(hsotg, qh); + if (dwc2_assign_and_init_hc(hsotg, qh)) + break; /* * Move the QH from the periodic ready schedule to the @@ -884,13 +900,21 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( num_channels = hsotg->core_params->host_channels; qh_ptr = hsotg->non_periodic_sched_inactive.next; while (qh_ptr != &hsotg->non_periodic_sched_inactive) { - if (hsotg->non_periodic_channels >= num_channels - + if (hsotg->core_params->uframe_sched <= 0 && + hsotg->non_periodic_channels >= num_channels - hsotg->periodic_channels) break; if (list_empty(&hsotg->free_hc_list)) break; qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); - dwc2_assign_and_init_hc(hsotg, qh); + if (hsotg->core_params->uframe_sched > 0) { + if (hsotg->available_host_channels < 1) + break; + hsotg->available_host_channels--; + } + + if (dwc2_assign_and_init_hc(hsotg, qh)) + break; /* * Move the QH from the non-periodic inactive schedule to the @@ -905,7 +929,8 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( else ret_val = DWC2_TRANSACTION_ALL; - hsotg->non_periodic_channels++; + if (hsotg->core_params->uframe_sched <= 0) + hsotg->non_periodic_channels++; } return ret_val; @@ -2848,6 +2873,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq, hsotg->hc_ptr_array[i] = channel; } + if (hsotg->core_params->uframe_sched > 0) + dwc2_hcd_init_usecs(hsotg); + /* Initialize hsotg start work */ INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func); diff --git a/drivers/staging/dwc2/hcd.h b/drivers/staging/dwc2/hcd.h index cc0a11708319..89a5484f5b74 100644 --- a/drivers/staging/dwc2/hcd.h +++ b/drivers/staging/dwc2/hcd.h @@ -238,6 +238,7 @@ enum dwc2_transaction_type { * @interval: Interval between transfers in (micro)frames * @sched_frame: (Micro)frame to initialize a periodic transfer. * The transfer executes in the following (micro)frame. + * @frame_usecs: Internal variable used by the microframe scheduler * @start_split_frame: (Micro)frame at which last start split was initialized * @ntd: Actual number of transfer descriptors in a list * @dw_align_buf: Used instead of original buffer if its physical address @@ -271,6 +272,7 @@ struct dwc2_qh { u16 usecs; u16 interval; u16 sched_frame; + u16 frame_usecs[8]; u16 start_split_frame; u16 ntd; u8 *dw_align_buf; @@ -463,6 +465,7 @@ extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, /* Schedule Queue Functions */ /* Implemented in hcd_queue.c */ +extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg); extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); diff --git a/drivers/staging/dwc2/hcd_ddma.c b/drivers/staging/dwc2/hcd_ddma.c index 69070f4442a8..c7d434519776 100644 --- a/drivers/staging/dwc2/hcd_ddma.c +++ b/drivers/staging/dwc2/hcd_ddma.c @@ -271,10 +271,14 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg, { struct dwc2_host_chan *chan = qh->channel; - if (dwc2_qh_is_non_per(qh)) - hsotg->non_periodic_channels--; - else + if (dwc2_qh_is_non_per(qh)) { + if (hsotg->core_params->uframe_sched > 0) + hsotg->available_host_channels++; + else + hsotg->non_periodic_channels--; + } else { dwc2_update_frame_list(hsotg, qh, 0); + } /* * The condition is added to prevent double cleanup try in case of @@ -370,7 +374,8 @@ void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC || qh->ep_type == USB_ENDPOINT_XFER_INT) && - !hsotg->periodic_channels && hsotg->frame_list) { + (hsotg->core_params->uframe_sched > 0 || + !hsotg->periodic_channels) && hsotg->frame_list) { dwc2_per_sched_disable(hsotg); dwc2_frame_list_free(hsotg); } diff --git a/drivers/staging/dwc2/hcd_intr.c b/drivers/staging/dwc2/hcd_intr.c index e143f69939f5..cad433a75aba 100644 --- a/drivers/staging/dwc2/hcd_intr.c +++ b/drivers/staging/dwc2/hcd_intr.c @@ -748,18 +748,23 @@ cleanup: dwc2_hc_cleanup(hsotg, chan); list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list); - switch (chan->ep_type) { - case USB_ENDPOINT_XFER_CONTROL: - case USB_ENDPOINT_XFER_BULK: - hsotg->non_periodic_channels--; - break; - default: - /* - * Don't release reservations for periodic channels here. - * That's done when a periodic transfer is descheduled (i.e. - * when the QH is removed from the periodic schedule). - */ - break; + if (hsotg->core_params->uframe_sched > 0) { + hsotg->available_host_channels++; + } else { + switch (chan->ep_type) { + case USB_ENDPOINT_XFER_CONTROL: + case USB_ENDPOINT_XFER_BULK: + hsotg->non_periodic_channels--; + break; + default: + /* + * Don't release reservations for periodic channels + * here. That's done when a periodic transfer is + * descheduled (i.e. when the QH is removed from the + * periodic schedule). + */ + break; + } } haintmsk = readl(hsotg->regs + HAINTMSK); diff --git a/drivers/staging/dwc2/hcd_queue.c b/drivers/staging/dwc2/hcd_queue.c index b1980ef28fa3..f200f1f6e1c6 100644 --- a/drivers/staging/dwc2/hcd_queue.c +++ b/drivers/staging/dwc2/hcd_queue.c @@ -251,12 +251,12 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) * * @hsotg: The HCD state structure for the DWC OTG controller * - * Return: 0 if successful, negative error code otherise + * Return: 0 if successful, negative error code otherwise */ static int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg) { /* - * Currently assuming that there is a dedicated host channnel for + * Currently assuming that there is a dedicated host channel for * each periodic transaction plus at least one host channel for * non-periodic transactions */ @@ -324,6 +324,146 @@ static int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg, } /** + * Microframe scheduler + * track the total use in hsotg->frame_usecs + * keep each qh use in qh->frame_usecs + * when surrendering the qh then donate the time back + */ +static const unsigned short max_uframe_usecs[] = { + 100, 100, 100, 100, 100, 100, 30, 0 +}; + +void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg) +{ + int i; + + for (i = 0; i < 8; i++) + hsotg->frame_usecs[i] = max_uframe_usecs[i]; +} + +static int dwc2_find_single_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ + unsigned short utime = qh->usecs; + int done = 0; + int i = 0; + int ret = -1; + + while (!done) { + /* At the start hsotg->frame_usecs[i] = max_uframe_usecs[i] */ + if (utime <= hsotg->frame_usecs[i]) { + hsotg->frame_usecs[i] -= utime; + qh->frame_usecs[i] += utime; + ret = i; + done = 1; + } else { + i++; + if (i == 8) + done = 1; + } + } + + return ret; +} + +/* + * use this for FS apps that can span multiple uframes + */ +static int dwc2_find_multi_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ + unsigned short utime = qh->usecs; + unsigned short xtime; + int t_left = utime; + int done = 0; + int i = 0; + int j; + int ret = -1; + + while (!done) { + if (hsotg->frame_usecs[i] <= 0) { + i++; + if (i == 8) { + ret = -1; + done = 1; + } + continue; + } + + /* + * we need n consecutive slots so use j as a start slot + * j plus j+1 must be enough time (for now) + */ + xtime = hsotg->frame_usecs[i]; + for (j = i + 1; j < 8; j++) { + /* + * if we add this frame remaining time to xtime we may + * be OK, if not we need to test j for a complete frame + */ + if (xtime + hsotg->frame_usecs[j] < utime) { + if (hsotg->frame_usecs[j] < + max_uframe_usecs[j]) { + ret = -1; + break; + } + } + if (xtime >= utime) { + ret = i; + break; + } + /* add the frame time to x time */ + xtime += hsotg->frame_usecs[j]; + /* we must have a fully available next frame or break */ + if (xtime < utime && + hsotg->frame_usecs[j] == max_uframe_usecs[j]) { + ret = -1; + break; + } + } + if (ret >= 0) { + t_left = utime; + for (j = i; t_left > 0 && j < 8; j++) { + t_left -= hsotg->frame_usecs[j]; + if (t_left <= 0) { + qh->frame_usecs[j] += + hsotg->frame_usecs[j] + t_left; + hsotg->frame_usecs[j] = -t_left; + ret = i; + done = 1; + } else { + qh->frame_usecs[j] += + hsotg->frame_usecs[j]; + hsotg->frame_usecs[j] = 0; + } + } + } else { + i++; + if (i == 8) { + ret = -1; + done = 1; + } + } + } + + return ret; +} + +static int dwc2_find_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ + int ret; + + if (qh->dev_speed == USB_SPEED_HIGH) { + /* if this is a hs transaction we need a full frame */ + ret = dwc2_find_single_uframe(hsotg, qh); + } else { + /* + * if this is a fs transaction we may need a sequence + * of frames + */ + ret = dwc2_find_multi_uframe(hsotg, qh); + } + return ret; +} + +/** * dwc2_check_max_xfer_size() - Checks that the max transfer size allowed in a * host channel is large enough to handle the maximum data transfer in a single * (micro)frame for a periodic transfer @@ -367,15 +507,35 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { int status; - status = dwc2_periodic_channel_available(hsotg); - if (status) { - dev_dbg(hsotg->dev, - "%s: No host channel available for periodic transfer\n", - __func__); - return status; + if (hsotg->core_params->uframe_sched > 0) { + int frame = -1; + + status = dwc2_find_uframe(hsotg, qh); + if (status == 0) + frame = 7; + else if (status > 0) + frame = status - 1; + + /* Set the new frame up */ + if (frame > -1) { + qh->sched_frame &= ~0x7; + qh->sched_frame |= (frame & 7); + } + + if (status != -1) + status = 0; + } else { + status = dwc2_periodic_channel_available(hsotg); + if (status) { + dev_info(hsotg->dev, + "%s: No host channel available for periodic transfer\n", + __func__); + return status; + } + + status = dwc2_check_periodic_bandwidth(hsotg, qh); } - status = dwc2_check_periodic_bandwidth(hsotg, qh); if (status) { dev_dbg(hsotg->dev, "%s: Insufficient periodic bandwidth for periodic transfer\n", @@ -399,8 +559,9 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_inactive); - /* Reserve periodic channel */ - hsotg->periodic_channels++; + if (hsotg->core_params->uframe_sched <= 0) + /* Reserve periodic channel */ + hsotg->periodic_channels++; /* Update claimed usecs per (micro)frame */ hsotg->periodic_usecs += qh->usecs; @@ -418,13 +579,22 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { - list_del_init(&qh->qh_list_entry); + int i; - /* Release periodic channel reservation */ - hsotg->periodic_channels--; + list_del_init(&qh->qh_list_entry); /* Update claimed usecs per (micro)frame */ hsotg->periodic_usecs -= qh->usecs; + + if (hsotg->core_params->uframe_sched > 0) { + for (i = 0; i < 8; i++) { + hsotg->frame_usecs[i] += qh->frame_usecs[i]; + qh->frame_usecs[i] = 0; + } + } else { + /* Release periodic channel reservation */ + hsotg->periodic_channels--; + } } /** @@ -581,7 +751,10 @@ void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, * Remove from periodic_sched_queued and move to * appropriate queue */ - if (qh->sched_frame == frame_number) + if ((hsotg->core_params->uframe_sched > 0 && + dwc2_frame_num_le(qh->sched_frame, frame_number)) + || (hsotg->core_params->uframe_sched <= 0 && + qh->sched_frame == frame_number)) list_move(&qh->qh_list_entry, &hsotg->periodic_sched_ready); else diff --git a/drivers/staging/dwc2/pci.c b/drivers/staging/dwc2/pci.c index 9020260d5df8..3d14c8870fca 100644 --- a/drivers/staging/dwc2/pci.c +++ b/drivers/staging/dwc2/pci.c @@ -84,6 +84,7 @@ static const struct dwc2_core_params dwc2_module_params = { .ts_dline = -1, .reload_ctl = -1, .ahbcfg = -1, + .uframe_sched = -1, }; /** diff --git a/drivers/staging/et131x/Module.symvers b/drivers/staging/et131x/Module.symvers new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/staging/et131x/Module.symvers diff --git a/drivers/staging/et131x/README b/drivers/staging/et131x/README index 9272a24ae61c..8da96a6d2c92 100644 --- a/drivers/staging/et131x/README +++ b/drivers/staging/et131x/README @@ -11,7 +11,12 @@ TODO: - Look at reducing the number of spinlocks - Simplify code in nic_rx_pkts(), when determining multicast_pkts_rcvd - Implement NAPI support - - in et131x_tx(), don't return NETDEV_TX_BUSY, just drop the packet with kfree_skb(). + - In et131x_tx(), don't return NETDEV_TX_BUSY, just drop the packet with kfree_skb(). + - Reduce the number of split lines by careful consideration of variable names etc. + - Do this in et131x.c: + struct fbr_lookup *fbr; + fbr = rx_local->fbr[id]; + Then replace all the instances of "rx_local->fbr[id]" with fbr. Please send patches to: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c index f73e58f5ef8d..7cd3d3470758 100644 --- a/drivers/staging/et131x/et131x.c +++ b/drivers/staging/et131x/et131x.c @@ -493,11 +493,8 @@ struct et131x_adapter { spinlock_t send_hw_lock; spinlock_t rcv_lock; - spinlock_t rcv_pend_lock; spinlock_t fbr_lock; - spinlock_t phy_lock; - /* Packet Filter and look ahead size */ u32 packet_filter; @@ -2777,10 +2774,9 @@ static void et131x_handle_recv_interrupt(struct et131x_adapter *adapter) adapter->net_stats.rx_packets++; /* Set the status on the packet, either resources or success */ - if (adapter->rx_ring.num_ready_recv < RFD_LOW_WATER_MARK) { - dev_warn(&adapter->pdev->dev, - "RFD's are running out\n"); - } + if (adapter->rx_ring.num_ready_recv < RFD_LOW_WATER_MARK) + dev_warn(&adapter->pdev->dev, "RFD's are running out\n"); + count++; } @@ -3100,11 +3096,10 @@ static int send_packet(struct sk_buff *skb, struct et131x_adapter *adapter) shbufva = (u16 *) skb->data; if ((shbufva[0] == 0xffff) && - (shbufva[1] == 0xffff) && (shbufva[2] == 0xffff)) { + (shbufva[1] == 0xffff) && (shbufva[2] == 0xffff)) tcb->flags |= FMP_DEST_BROAD; - } else if ((shbufva[0] & 0x3) == 0x0001) { + else if ((shbufva[0] & 0x3) == 0x0001) tcb->flags |= FMP_DEST_MULTI; - } } tcb->next = NULL; @@ -3926,9 +3921,7 @@ static struct et131x_adapter *et131x_adapter_init(struct net_device *netdev, spin_lock_init(&adapter->tcb_ready_qlock); spin_lock_init(&adapter->send_hw_lock); spin_lock_init(&adapter->rcv_lock); - spin_lock_init(&adapter->rcv_pend_lock); spin_lock_init(&adapter->fbr_lock); - spin_lock_init(&adapter->phy_lock); adapter->registry_jumbo_packet = 1514; /* 1514-9216 */ diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index 5190c8ac4e0a..1a1413d31af6 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -1,12 +1,8 @@ -//===================================================== -// CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved. -// -// -// This file is part of Express Card USB Driver -// -// $Id: -//==================================================== -// 20090926; aelias; removed compiler warnings; ubuntu 9.04; 2.6.28-15-generic +/* +* CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved. +* +* This file is part of Express Card USB Driver +*/ #include <linux/init.h> #include <linux/kernel.h> @@ -111,19 +107,8 @@ struct dsp_image_info { }; -//--------------------------------------------------------------------------- -// Function: check_usb_db -// -// Parameters: struct ft1000_usb - device structure -// -// Returns: 0 - success -// -// Description: This function checks if the doorbell register is cleared -// -// Notes: -// -//--------------------------------------------------------------------------- -static u32 check_usb_db (struct ft1000_usb *ft1000dev) +/* checks if the doorbell register is cleared */ +static u32 check_usb_db(struct ft1000_usb *ft1000dev) { int loopcnt; u16 temp; @@ -169,20 +154,7 @@ static u32 check_usb_db (struct ft1000_usb *ft1000dev) return HANDSHAKE_MAG_TIMEOUT_VALUE; } -//--------------------------------------------------------------------------- -// Function: get_handshake -// -// Parameters: struct ft1000_usb - device structure -// u16 expected_value - the handshake value expected -// -// Returns: handshakevalue - success -// HANDSHAKE_TIMEOUT_VALUE - failure -// -// Description: This function gets the handshake and compare with the expected value -// -// Notes: -// -//--------------------------------------------------------------------------- +/* gets the handshake and compares it with the expected value */ static u16 get_handshake(struct ft1000_usb *ft1000dev, u16 expected_value) { u16 handshake; @@ -229,20 +201,7 @@ static u16 get_handshake(struct ft1000_usb *ft1000dev, u16 expected_value) return HANDSHAKE_TIMEOUT_VALUE; } -//--------------------------------------------------------------------------- -// Function: put_handshake -// -// Parameters: struct ft1000_usb - device structure -// u16 handshake_value - handshake to be written -// -// Returns: none -// -// Description: This function write the handshake value to the handshake location -// in DPRAM -// -// Notes: -// -//--------------------------------------------------------------------------- +/* write the handshake value to the handshake location */ static void put_handshake(struct ft1000_usb *ft1000dev,u16 handshake_value) { u32 tempx; @@ -316,18 +275,6 @@ static void put_handshake_usb(struct ft1000_usb *ft1000dev,u16 handshake_value) for (i=0; i<1000; i++); } -//--------------------------------------------------------------------------- -// Function: get_request_type -// -// Parameters: struct ft1000_usb - device structure -// -// Returns: request type - success -// -// Description: This function returns the request type -// -// Notes: -// -//--------------------------------------------------------------------------- static u16 get_request_type(struct ft1000_usb *ft1000dev) { u16 request_type; @@ -380,18 +327,6 @@ static u16 get_request_type_usb(struct ft1000_usb *ft1000dev) return request_type; } -//--------------------------------------------------------------------------- -// Function: get_request_value -// -// Parameters: struct ft1000_usb - device structure -// -// Returns: request value - success -// -// Description: This function returns the request value -// -// Notes: -// -//--------------------------------------------------------------------------- static long get_request_value(struct ft1000_usb *ft1000dev) { u32 value; @@ -416,19 +351,7 @@ static long get_request_value(struct ft1000_usb *ft1000dev) } -//--------------------------------------------------------------------------- -// Function: put_request_value -// -// Parameters: struct ft1000_usb - device structure -// long lvalue - value to be put into DPRAM location DWNLD_MAG1_SIZE_LOC -// -// Returns: none -// -// Description: This function writes a value to DWNLD_MAG1_SIZE_LOC -// -// Notes: -// -//--------------------------------------------------------------------------- +/* writes a value to DWNLD_MAG1_SIZE_LOC */ static void put_request_value(struct ft1000_usb *ft1000dev, long lvalue) { u32 tempx; @@ -441,18 +364,7 @@ static void put_request_value(struct ft1000_usb *ft1000dev, long lvalue) -//--------------------------------------------------------------------------- -// Function: hdr_checksum -// -// Parameters: struct pseudo_hdr *pHdr - Pseudo header pointer -// -// Returns: checksum - success -// -// Description: This function returns the checksum of the pseudo header -// -// Notes: -// -//--------------------------------------------------------------------------- +/* returns the checksum of the pseudo header */ static u16 hdr_checksum(struct pseudo_hdr *pHdr) { u16 *usPtr = (u16 *)pHdr; @@ -477,23 +389,12 @@ static int check_buffers(u16 *buff_w, u16 *buff_r, int len, int offset) return 0; } -//--------------------------------------------------------------------------- -// Function: write_blk -// -// Parameters: struct ft1000_usb - device structure -// u16 **pUsFile - DSP image file pointer in u16 -// u8 **pUcFile - DSP image file pointer in u8 -// long word_length - length of the buffer to be written -// to DPRAM -// -// Returns: STATUS_SUCCESS - success -// STATUS_FAILURE - failure -// -// Description: This function writes a block of DSP image to DPRAM -// -// Notes: -// -//--------------------------------------------------------------------------- +/* writes a block of DSP image to DPRAM + * Parameters: struct ft1000_usb - device structure + * u16 **pUsFile - DSP image file pointer in u16 + * u8 **pUcFile - DSP image file pointer in u8 + * long word_length - length of the buffer to be written to DPRAM + */ static u32 write_blk (struct ft1000_usb *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) { u32 Status = STATUS_SUCCESS; @@ -616,23 +517,12 @@ static void usb_dnld_complete (struct urb *urb) //DEBUG("****** usb_dnld_complete\n"); } -//--------------------------------------------------------------------------- -// Function: write_blk_fifo -// -// Parameters: struct ft1000_usb - device structure -// u16 **pUsFile - DSP image file pointer in u16 -// u8 **pUcFile - DSP image file pointer in u8 -// long word_length - length of the buffer to be written -// to DPRAM -// -// Returns: STATUS_SUCCESS - success -// STATUS_FAILURE - failure -// -// Description: This function writes a block of DSP image to DPRAM -// -// Notes: -// -//--------------------------------------------------------------------------- +/* writes a block of DSP image to DPRAM + * Parameters: struct ft1000_usb - device structure + * u16 **pUsFile - DSP image file pointer in u16 + * u8 **pUcFile - DSP image file pointer in u8 + * long word_length - length of the buffer to be written to DPRAM + */ static u32 write_blk_fifo(struct ft1000_usb *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) { @@ -664,18 +554,7 @@ static u32 write_blk_fifo(struct ft1000_usb *ft1000dev, u16 **pUsFile, return Status; } -//--------------------------------------------------------------------------- -// -// Function: scram_dnldr -// -// Synopsis: Scramble downloader for Harley based ASIC via USB interface -// -// Arguments: pFileStart - pointer to start of file -// FileLength - file length -// -// Returns: status - return code -//--------------------------------------------------------------------------- - +/* Scramble downloader for Harley based ASIC via USB interface */ u16 scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart, u32 FileLength) { @@ -1036,7 +915,7 @@ u16 scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart, status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, - (u8 *) & templong); + (u8 *) &templong); } break; @@ -1137,13 +1016,13 @@ u16 scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart, if (pseudo_header->checksum == hdr_checksum(pseudo_header)) { if (pseudo_header->portdest != - 0x80 /* Dsp OAM */ ) { + 0x80 /* Dsp OAM */) { state = STATE_DONE_PROV; break; } pseudo_header_len = ntohs(pseudo_header->length); /* Byte length for PROV records */ - // Get buffer for provisioning data + /* Get buffer for provisioning data */ pbuffer = kmalloc((pseudo_header_len + sizeof(struct pseudo_hdr)), @@ -1201,9 +1080,8 @@ u16 scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart, break; } /* End Switch */ - if (status != STATUS_SUCCESS) { + if (status != STATUS_SUCCESS) break; - } /**** // Check if Card is present diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index ff92f34e4746..62df009e5ac7 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -2394,7 +2394,8 @@ static int fwserial_create(struct fw_unit *unit) list_del_rcu(&serial->list); if (create_loop_dev) - tty_unregister_device(fwloop_driver, loop_idx(serial->ports[j])); + tty_unregister_device(fwloop_driver, + loop_idx(serial->ports[j])); unregister_ttys: for (--j; j >= 0; --j) tty_unregister_device(fwtty_driver, serial->ports[j]->index); diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c index bc0d510fb0af..c57a6ba5d010 100644 --- a/drivers/staging/gdm724x/gdm_lte.c +++ b/drivers/staging/gdm724x/gdm_lte.c @@ -110,7 +110,7 @@ static int gdm_lte_rx(struct sk_buff *skb, struct nic *nic, int nic_type) return 0; } -int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type) +static int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type) { struct nic *nic = netdev_priv(skb_in->dev); struct sk_buff *skb_out; @@ -186,7 +186,7 @@ int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type) return 0; } -int icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len) +static int icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len) { unsigned short *w = ptr; int sum = 0; @@ -226,7 +226,7 @@ int icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len) return sum; } -int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) +static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) { struct nic *nic = netdev_priv(skb_in->dev); struct sk_buff *skb_out; diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c index 5b1ef4000d0f..62163673976c 100644 --- a/drivers/staging/gdm724x/gdm_mux.c +++ b/drivers/staging/gdm724x/gdm_mux.c @@ -26,7 +26,7 @@ #include "gdm_mux.h" -struct workqueue_struct *mux_rx_wq; +static struct workqueue_struct *mux_rx_wq; static u16 packet_type[TTY_MAX_COUNT] = {0xF011, 0xF010}; @@ -51,7 +51,7 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -int packet_type_to_index(u16 packetType) +static int packet_type_to_index(u16 packetType) { int i; @@ -96,12 +96,12 @@ static struct mux_rx *alloc_mux_rx(void) { struct mux_rx *r = NULL; - r = kzalloc(sizeof(struct mux_rx), GFP_ATOMIC); + r = kzalloc(sizeof(struct mux_rx), GFP_KERNEL); if (!r) return NULL; - r->urb = usb_alloc_urb(0, GFP_ATOMIC); - r->buf = kmalloc(MUX_RX_MAX_SIZE, GFP_ATOMIC); + r->urb = usb_alloc_urb(0, GFP_KERNEL); + r->buf = kmalloc(MUX_RX_MAX_SIZE, GFP_KERNEL); if (!r->urb || !r->buf) { usb_free_urb(r->urb); kfree(r->buf); @@ -541,7 +541,7 @@ static int gdm_mux_probe(struct usb_interface *intf, const struct usb_device_id ret = init_usb(mux_dev); if (ret) - goto err_free_tty; + goto err_free_usb; tty_dev->priv_dev = (void *)mux_dev; tty_dev->send_func = gdm_mux_send; @@ -565,8 +565,8 @@ static int gdm_mux_probe(struct usb_interface *intf, const struct usb_device_id err_unregister_tty: unregister_lte_tty_device(tty_dev); +err_free_usb: release_usb(mux_dev); -err_free_tty: kfree(tty_dev); err_free_mux: kfree(mux_dev); diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c index 0247a2055e8d..c0f7cd75116b 100644 --- a/drivers/staging/gdm724x/gdm_tty.c +++ b/drivers/staging/gdm724x/gdm_tty.c @@ -171,7 +171,8 @@ static void gdm_tty_send_complete(void *arg) tty_port_tty_wakeup(&gdm->port); } -static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf, int len) +static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf, + int len) { struct gdm *gdm = tty->driver_data; int remain = len; @@ -185,7 +186,8 @@ static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf, int l return 0; while (1) { - sending_len = remain > MUX_TX_MAX_SIZE ? MUX_TX_MAX_SIZE : remain; + sending_len = remain > MUX_TX_MAX_SIZE ? MUX_TX_MAX_SIZE : + remain; gdm_tty_send(gdm, (void *)(buf+sent_len), sending_len, @@ -247,7 +249,8 @@ int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device) gdm->minor = j; gdm->tty_dev = tty_dev; - tty_port_register_device(&gdm->port, gdm_driver[i], gdm->minor, device); + tty_port_register_device(&gdm->port, gdm_driver[i], + gdm->minor, device); } for (i = 0; i < MAX_ISSUE_NUM; i++) @@ -309,7 +312,8 @@ int register_lte_tty_driver(void) tty_driver->major = GDM_TTY_MAJOR; tty_driver->type = TTY_DRIVER_TYPE_SERIAL; tty_driver->subtype = SERIAL_TYPE_NORMAL; - tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_driver->flags = TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV; tty_driver->init_termios = tty_std_termios; tty_driver->init_termios.c_cflag = B9600 | CS8 | HUPCL | CLOCAL; tty_driver->init_termios.c_lflag = ISIG | ICANON | IEXTEN; diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index cf32ae099cd6..35154d60faf6 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -502,7 +502,7 @@ inline int find_type_by_name(const char *name, const char *type) inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify) { - int ret; + int ret = 0; FILE *sysfsfp; int test; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO index 04c23262f8e2..c22a0edd1528 100644 --- a/drivers/staging/iio/TODO +++ b/drivers/staging/iio/TODO @@ -13,6 +13,17 @@ Would be nice 3) Expand device set. Lots of other maxim adc's have very similar interfaces. +MXS LRADC driver: +This is a classic MFD device as it combines the following subdevices + - touchscreen controller (input subsystem related device) + - general purpose ADC channels + - battery voltage monitor (power subsystem related device) + - die temperature monitor (thermal management) + +At least the battery voltage and die temperature feature is required in-kernel +by a driver of the SoC's battery charging unit to avoid any damage to the +silicon and the battery. + TSL2561 Would be nice 1) Open question of userspace vs kernel space balance when diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c index 5c289614357c..4c9364b63c77 100644 --- a/drivers/staging/iio/accel/adis16220_core.c +++ b/drivers/staging/iio/accel/adis16220_core.c @@ -102,7 +102,6 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev, int addr) { struct adis16220_state *st = iio_priv(indio_dev); - struct spi_message msg; struct spi_transfer xfers[] = { { .tx_buf = st->tx, @@ -147,10 +146,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev, } xfers[1].len = count; - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->adis.spi, &msg); + ret = spi_sync_transfer(st->adis.spi, xfers, ARRAY_SIZE(xfers)); if (ret) { mutex_unlock(&st->buf_lock); diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index bb852dc9c987..2789be381f1b 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -190,15 +190,26 @@ static u8 lis3l02dq_axis_map[3][3] = { }; static int lis3l02dq_read_thresh(struct iio_dev *indio_dev, - u64 e, - int *val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { - return lis3l02dq_read_reg_s16(indio_dev, LIS3L02DQ_REG_THS_L_ADDR, val); + int ret; + + ret = lis3l02dq_read_reg_s16(indio_dev, LIS3L02DQ_REG_THS_L_ADDR, val); + if (ret) + return ret; + return IIO_VAL_INT; } static int lis3l02dq_write_thresh(struct iio_dev *indio_dev, - u64 event_code, - int val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { u16 value = val; return lis3l02dq_spi_write_reg_s16(indio_dev, @@ -503,9 +514,19 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private) return IRQ_HANDLED; } -#define LIS3L02DQ_EVENT_MASK \ - (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \ - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) +static const struct iio_event_spec lis3l02dq_event[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), + } +}; #define LIS3L02DQ_CHAN(index, mod) \ { \ @@ -523,7 +544,8 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private) .realbits = 12, \ .storagebits = 16, \ }, \ - .event_mask = LIS3L02DQ_EVENT_MASK, \ + .event_spec = lis3l02dq_event, \ + .num_event_specs = ARRAY_SIZE(lis3l02dq_event), \ } static const struct iio_chan_spec lis3l02dq_channels[] = { @@ -535,14 +557,14 @@ static const struct iio_chan_spec lis3l02dq_channels[] = { static int lis3l02dq_read_event_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { u8 val; int ret; - u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 + - (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING))); + u8 mask = (1 << (chan->channel2*2 + (dir == IIO_EV_DIR_RISING))); ret = lis3l02dq_spi_read_reg_8(indio_dev, LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, &val); @@ -587,16 +609,16 @@ error_ret: } static int lis3l02dq_write_event_config(struct iio_dev *indio_dev, - u64 event_code, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) { int ret = 0; u8 val, control; u8 currentlyset; bool changed = false; - u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 + - (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING))); + u8 mask = (1 << (chan->channel2*2 + (dir == IIO_EV_DIR_RISING))); mutex_lock(&indio_dev->mlock); /* read current control */ @@ -654,10 +676,10 @@ static const struct attribute_group lis3l02dq_attribute_group = { static const struct iio_info lis3l02dq_info = { .read_raw = &lis3l02dq_read_raw, .write_raw = &lis3l02dq_write_raw, - .read_event_value = &lis3l02dq_read_thresh, - .write_event_value = &lis3l02dq_write_thresh, - .write_event_config = &lis3l02dq_write_event_config, - .read_event_config = &lis3l02dq_read_event_config, + .read_event_value_new = &lis3l02dq_read_thresh, + .write_event_value_new = &lis3l02dq_write_thresh, + .write_event_config_new = &lis3l02dq_write_event_config, + .read_event_config_new = &lis3l02dq_read_event_config, .driver_module = THIS_MODULE, .attrs = &lis3l02dq_attribute_group, }; diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index 5b8f0f6c9938..79cefe0a516a 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -111,7 +111,7 @@ static int lis3l02dq_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) { int ret, i; - u8 *rx_array ; + u8 *rx_array; s16 *data = (s16 *)buf; int scan_count = bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); @@ -146,11 +146,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) len = lis3l02dq_get_buffer_element(indio_dev, data); - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - *(s64 *)((u8 *)data + ALIGN(len, sizeof(s64))) - = pf->timestamp; - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers_with_timestamp(indio_dev, data, pf->timestamp); kfree(data); done: @@ -264,8 +260,7 @@ static int lis3l02dq_trig_try_reen(struct iio_trigger *trig) else break; if (i == 5) - printk(KERN_INFO - "Failed to clear the interrupt for lis3l02dq\n"); + pr_info("Failed to clear the interrupt for lis3l02dq\n"); /* irq reenabled so success! */ return 0; @@ -387,7 +382,6 @@ error_ret: } static const struct iio_buffer_setup_ops lis3l02dq_buffer_setup_ops = { - .preenable = &iio_sw_buffer_preenable, .postenable = &lis3l02dq_buffer_postenable, .predisable = &lis3l02dq_buffer_predisable, }; @@ -401,7 +395,7 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev) if (!buffer) return -ENOMEM; - indio_dev->buffer = buffer; + iio_device_attach_buffer(indio_dev, buffer); buffer->scan_timestamp = true; indio_dev->setup_ops = &lis3l02dq_buffer_setup_ops; diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 48a25ba290f5..c49e6ef9d05f 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -419,8 +419,11 @@ static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR, static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); -#define SCA3000_EVENT_MASK \ - (IIO_EV_BIT(IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING)) +static const struct iio_event_spec sca3000_event = { + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), +}; #define SCA3000_CHAN(index, mod) \ { \ @@ -437,7 +440,8 @@ static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); .storagebits = 16, \ .shift = 5, \ }, \ - .event_mask = SCA3000_EVENT_MASK, \ + .event_spec = &sca3000_event, \ + .num_event_specs = 1, \ } static const struct iio_chan_spec sca3000_channels[] = { @@ -624,9 +628,9 @@ static ssize_t sca3000_set_frequency(struct device *dev, struct sca3000_state *st = iio_priv(indio_dev); int ret, base_freq = 0; int ctrlval; - long val; + int val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtoint(buf, 10, &val); if (ret) return ret; @@ -703,12 +707,15 @@ static IIO_CONST_ATTR_TEMP_OFFSET("-214.6"); * sca3000_read_thresh() - query of a threshold **/ static int sca3000_read_thresh(struct iio_dev *indio_dev, - u64 e, - int *val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { int ret, i; struct sca3000_state *st = iio_priv(indio_dev); - int num = IIO_EVENT_CODE_EXTRACT_MODIFIER(e); + int num = chan->channel2; mutex_lock(&st->lock); ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]); mutex_unlock(&st->lock); @@ -724,18 +731,21 @@ static int sca3000_read_thresh(struct iio_dev *indio_dev, ARRAY_SIZE(st->info->mot_det_mult_xz)) *val += st->info->mot_det_mult_xz[i]; - return 0; + return IIO_VAL_INT; } /** * sca3000_write_thresh() control of threshold **/ static int sca3000_write_thresh(struct iio_dev *indio_dev, - u64 e, - int val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct sca3000_state *st = iio_priv(indio_dev); - int num = IIO_EVENT_CODE_EXTRACT_MODIFIER(e); + int num = chan->channel2; int ret; int i; u8 nonlinear = 0; @@ -866,12 +876,14 @@ done: * sca3000_read_event_config() what events are enabled **/ static int sca3000_read_event_config(struct iio_dev *indio_dev, - u64 e) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { struct sca3000_state *st = iio_priv(indio_dev); int ret; u8 protect_mask = 0x03; - int num = IIO_EVENT_CODE_EXTRACT_MODIFIER(e); + int num = chan->channel2; /* read current value of mode register */ mutex_lock(&st->lock); @@ -931,12 +943,12 @@ static ssize_t sca3000_set_free_fall_mode(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); - long val; + u8 val; int ret; u8 protect_mask = SCA3000_FREE_FALL_DETECT; mutex_lock(&st->lock); - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; @@ -969,13 +981,15 @@ error_ret: * this mode is disabled. Currently normal mode is assumed. **/ static int sca3000_write_event_config(struct iio_dev *indio_dev, - u64 e, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) { struct sca3000_state *st = iio_priv(indio_dev); int ret, ctrlval; u8 protect_mask = 0x03; - int num = IIO_EVENT_CODE_EXTRACT_MODIFIER(e); + int num = chan->channel2; mutex_lock(&st->lock); /* First read the motion detector config to find out if @@ -1112,20 +1126,20 @@ static const struct iio_info sca3000_info = { .attrs = &sca3000_attribute_group, .read_raw = &sca3000_read_raw, .event_attrs = &sca3000_event_attribute_group, - .read_event_value = &sca3000_read_thresh, - .write_event_value = &sca3000_write_thresh, - .read_event_config = &sca3000_read_event_config, - .write_event_config = &sca3000_write_event_config, + .read_event_value_new = &sca3000_read_thresh, + .write_event_value_new = &sca3000_write_thresh, + .read_event_config_new = &sca3000_read_event_config, + .write_event_config_new = &sca3000_write_event_config, .driver_module = THIS_MODULE, }; static const struct iio_info sca3000_info_with_temp = { .attrs = &sca3000_attribute_group_with_temp, .read_raw = &sca3000_read_raw, - .read_event_value = &sca3000_read_thresh, - .write_event_value = &sca3000_write_thresh, - .read_event_config = &sca3000_read_event_config, - .write_event_config = &sca3000_write_event_config, + .read_event_value_new = &sca3000_read_thresh, + .write_event_value_new = &sca3000_write_thresh, + .read_event_config_new = &sca3000_read_event_config, + .write_event_config_new = &sca3000_write_event_config, .driver_module = THIS_MODULE, }; diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index 3e5e860aa38e..ea0af6d81d2b 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -177,11 +177,11 @@ static ssize_t sca3000_set_ring_int(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long val; + u8 val; int ret; mutex_lock(&st->lock); - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); @@ -252,7 +252,7 @@ static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev) struct iio_buffer *buf; struct iio_hw_buffer *ring; - ring = kzalloc(sizeof *ring, GFP_KERNEL); + ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) return NULL; @@ -265,7 +265,7 @@ static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev) return buf; } -static inline void sca3000_rb_free(struct iio_buffer *r) +static void sca3000_ring_release(struct iio_buffer *r) { kfree(iio_to_hw_buf(r)); } @@ -274,23 +274,28 @@ static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = { .read_first_n = &sca3000_read_first_n_hw_rb, .get_length = &sca3000_ring_get_length, .get_bytes_per_datum = &sca3000_ring_get_bytes_per_datum, + .release = sca3000_ring_release, }; int sca3000_configure_ring(struct iio_dev *indio_dev) { - indio_dev->buffer = sca3000_rb_allocate(indio_dev); - if (indio_dev->buffer == NULL) + struct iio_buffer *buffer; + + buffer = sca3000_rb_allocate(indio_dev); + if (buffer == NULL) return -ENOMEM; indio_dev->modes |= INDIO_BUFFER_HARDWARE; indio_dev->buffer->access = &sca3000_ring_access_funcs; + iio_device_attach_buffer(indio_dev, buffer); + return 0; } void sca3000_unconfigure_ring(struct iio_dev *indio_dev) { - sca3000_rb_free(indio_dev->buffer); + iio_buffer_put(indio_dev->buffer); } static inline diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index cabc7a367db5..1cf476484d77 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -102,7 +102,7 @@ config AD7280 config LPC32XX_ADC tristate "NXP LPC32XX ADC" - depends on ARCH_LPC32XX + depends on ARCH_LPC32XX || COMPILE_TEST help Say yes here to build support for the integrated ADC inside the LPC32XX SoC. Note that this feature uses the same hardware as the @@ -113,7 +113,8 @@ config LPC32XX_ADC config MXS_LRADC tristate "Freescale i.MX23/i.MX28 LRADC" - depends on ARCH_MXS + depends on ARCH_MXS || COMPILE_TEST + select STMP_DEVICE select IIO_BUFFER select IIO_TRIGGERED_BUFFER help @@ -125,7 +126,7 @@ config MXS_LRADC config SPEAR_ADC tristate "ST SPEAr ADC" - depends on PLAT_SPEAR + depends on PLAT_SPEAR || COMPILE_TEST help Say yes here to build support for the integrated ADC inside the ST SPEAr SoC. Provides direct access via sysfs. diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 3283e2829536..83bb44b38152 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -623,17 +623,17 @@ static int ad7192_probe(struct spi_device *spi) return -ENODEV; } - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); - st->reg = regulator_get(&spi->dev, "vcc"); + st->reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; voltage_uv = regulator_get_voltage(st->reg); } @@ -677,11 +677,6 @@ error_remove_trigger: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - - iio_device_free(indio_dev); return ret; } @@ -694,10 +689,8 @@ static int ad7192_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ad_sd_cleanup_buffer_and_trigger(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } return 0; } diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index c19618bc37c4..8209fa542a8a 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -783,7 +783,6 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, long m) { struct ad7280_state *st = iio_priv(indio_dev); - unsigned int scale_uv; int ret; switch (m) { @@ -804,13 +803,12 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6) - scale_uv = (4000 * 1000) >> AD7280A_BITS; + *val = 4000; else - scale_uv = (5000 * 1000) >> AD7280A_BITS; + *val = 5000; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; + *val2 = AD7280A_BITS; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } @@ -835,8 +833,9 @@ static int ad7280_probe(struct spi_device *spi) int ret; const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890}; const unsigned short nAVG[4] = {1, 2, 4, 8}; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -860,7 +859,7 @@ static int ad7280_probe(struct spi_device *spi) ret = ad7280_chain_setup(st); if (ret < 0) - goto error_free_device; + return ret; st->slave_num = ret; st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH; @@ -891,7 +890,7 @@ static int ad7280_probe(struct spi_device *spi) ret = ad7280_channel_init(st); if (ret < 0) - goto error_free_device; + return ret; indio_dev->num_channels = ret; indio_dev->channels = st->channels; @@ -940,9 +939,6 @@ error_free_attr: error_free_channels: kfree(st->channels); -error_free_device: - iio_device_free(indio_dev); - return ret; } @@ -960,7 +956,6 @@ static int ad7280_remove(struct spi_device *spi) kfree(st->channels); kfree(st->iio_attr); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c index a2e61c2fc8d1..d13f8aeeb62f 100644 --- a/drivers/staging/iio/adc/ad7291.c +++ b/drivers/staging/iio/adc/ad7291.c @@ -164,97 +164,14 @@ static irqreturn_t ad7291_event_handler(int irq, void *private) return IRQ_HANDLED; } -static inline ssize_t ad7291_show_hyst(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7291_chip_info *chip = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u16 data; - int ret; - - ret = ad7291_i2c_read(chip, this_attr->address, &data); - if (ret < 0) - return ret; - - return sprintf(buf, "%d\n", data & AD7291_VALUE_MASK); -} - -static inline ssize_t ad7291_set_hyst(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7291_chip_info *chip = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u16 data; - int ret; - - ret = kstrtou16(buf, 10, &data); - - if (ret < 0) - return ret; - if (data > AD7291_VALUE_MASK) - return -EINVAL; - - ret = ad7291_i2c_write(chip, this_attr->address, data); - if (ret < 0) - return ret; - - return len; -} - -static IIO_DEVICE_ATTR(in_temp0_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, - AD7291_HYST(8)); -static IIO_DEVICE_ATTR(in_voltage0_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(0)); -static IIO_DEVICE_ATTR(in_voltage1_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(1)); -static IIO_DEVICE_ATTR(in_voltage2_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(2)); -static IIO_DEVICE_ATTR(in_voltage3_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(3)); -static IIO_DEVICE_ATTR(in_voltage4_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(4)); -static IIO_DEVICE_ATTR(in_voltage5_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(5)); -static IIO_DEVICE_ATTR(in_voltage6_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(6)); -static IIO_DEVICE_ATTR(in_voltage7_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(7)); - -static struct attribute *ad7291_event_attributes[] = { - &iio_dev_attr_in_temp0_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage0_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage1_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage2_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage3_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage4_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage5_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage6_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage7_thresh_both_hyst_raw.dev_attr.attr, - NULL, -}; - -static unsigned int ad7291_threshold_reg(u64 event_code) +static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan, + enum iio_event_direction dir, enum iio_event_info info) { unsigned int offset; - switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + switch (chan->type) { case IIO_VOLTAGE: - offset = IIO_EVENT_CODE_EXTRACT_CHAN(event_code); + offset = chan->channel; break; case IIO_TEMP: offset = 8; @@ -263,69 +180,78 @@ static unsigned int ad7291_threshold_reg(u64 event_code) return 0; } - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) - return AD7291_DATA_LOW(offset); - else - return AD7291_DATA_HIGH(offset); + switch (info) { + case IIO_EV_INFO_VALUE: + if (dir == IIO_EV_DIR_FALLING) + return AD7291_DATA_HIGH(offset); + else + return AD7291_DATA_LOW(offset); + case IIO_EV_INFO_HYSTERESIS: + return AD7291_HYST(offset); + default: + break; + } + return 0; } static int ad7291_read_event_value(struct iio_dev *indio_dev, - u64 event_code, - int *val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { struct ad7291_chip_info *chip = iio_priv(indio_dev); int ret; u16 uval; - ret = ad7291_i2c_read(chip, ad7291_threshold_reg(event_code), &uval); + ret = ad7291_i2c_read(chip, ad7291_threshold_reg(chan, dir, info), + &uval); if (ret < 0) return ret; - switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { - case IIO_VOLTAGE: + if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE) *val = uval & AD7291_VALUE_MASK; - return 0; - case IIO_TEMP: + + else *val = sign_extend32(uval, 11); - return 0; - default: - return -EINVAL; - }; + + return IIO_VAL_INT; } static int ad7291_write_event_value(struct iio_dev *indio_dev, - u64 event_code, - int val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct ad7291_chip_info *chip = iio_priv(indio_dev); - switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { - case IIO_VOLTAGE: + if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE) { if (val > AD7291_VALUE_MASK || val < 0) return -EINVAL; - break; - case IIO_TEMP: + } else { if (val > 2047 || val < -2048) return -EINVAL; - break; - default: - return -EINVAL; } - return ad7291_i2c_write(chip, ad7291_threshold_reg(event_code), val); + return ad7291_i2c_write(chip, ad7291_threshold_reg(chan, dir, info), + val); } static int ad7291_read_event_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { struct ad7291_chip_info *chip = iio_priv(indio_dev); /* To be enabled the channel must simply be on. If any are enabled we are in continuous sampling mode */ - switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + switch (chan->type) { case IIO_VOLTAGE: - if (chip->c_mask & - (1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN(event_code)))) + if (chip->c_mask & (1 << (15 - chan->channel))) return 1; else return 0; @@ -339,11 +265,14 @@ static int ad7291_read_event_config(struct iio_dev *indio_dev, } static int ad7291_write_event_config(struct iio_dev *indio_dev, - u64 event_code, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) { int ret = 0; struct ad7291_chip_info *chip = iio_priv(indio_dev); + unsigned int mask; u16 regval; mutex_lock(&chip->state_lock); @@ -354,16 +283,14 @@ static int ad7291_write_event_config(struct iio_dev *indio_dev, * Possible to disable temp as well but that makes single read tricky. */ - switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) { + mask = BIT(15 - chan->channel); + + switch (chan->type) { case IIO_VOLTAGE: - if ((!state) && (chip->c_mask & (1 << (15 - - IIO_EVENT_CODE_EXTRACT_CHAN(event_code))))) - chip->c_mask &= ~(1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN - (event_code))); - else if (state && (!(chip->c_mask & (1 << (15 - - IIO_EVENT_CODE_EXTRACT_CHAN(event_code)))))) - chip->c_mask |= (1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN - (event_code))); + if ((!state) && (chip->c_mask & mask)) + chip->c_mask &= ~mask; + else if (state && (!(chip->c_mask & mask))) + chip->c_mask |= mask; else break; @@ -473,6 +400,24 @@ static int ad7291_read_raw(struct iio_dev *indio_dev, } } +static const struct iio_event_spec ad7291_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + #define AD7291_VOLTAGE_CHAN(_chan) \ { \ .type = IIO_VOLTAGE, \ @@ -480,8 +425,8 @@ static int ad7291_read_raw(struct iio_dev *indio_dev, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .indexed = 1, \ .channel = _chan, \ - .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|\ - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) \ + .event_spec = ad7291_events, \ + .num_event_specs = ARRAY_SIZE(ad7291_events), \ } static const struct iio_chan_spec ad7291_channels[] = { @@ -500,23 +445,17 @@ static const struct iio_chan_spec ad7291_channels[] = { BIT(IIO_CHAN_INFO_SCALE), .indexed = 1, .channel = 0, - .event_mask = - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)| - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) + .event_spec = ad7291_events, + .num_event_specs = ARRAY_SIZE(ad7291_events), } }; -static struct attribute_group ad7291_event_attribute_group = { - .attrs = ad7291_event_attributes, -}; - static const struct iio_info ad7291_info = { .read_raw = &ad7291_read_raw, - .read_event_config = &ad7291_read_event_config, - .write_event_config = &ad7291_write_event_config, - .read_event_value = &ad7291_read_event_value, - .write_event_value = &ad7291_write_event_value, - .event_attrs = &ad7291_event_attribute_group, + .read_event_config_new = &ad7291_read_event_config, + .write_event_config_new = &ad7291_write_event_config, + .read_event_value_new = &ad7291_read_event_value, + .write_event_value_new = &ad7291_write_event_value, .driver_module = THIS_MODULE, }; @@ -528,21 +467,19 @@ static int ad7291_probe(struct i2c_client *client, struct iio_dev *indio_dev; int ret = 0; - indio_dev = iio_device_alloc(sizeof(*chip)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; chip = iio_priv(indio_dev); if (pdata && pdata->use_external_ref) { - chip->reg = regulator_get(&client->dev, "vref"); + chip->reg = devm_regulator_get(&client->dev, "vref"); if (IS_ERR(chip->reg)) - goto error_free; + return ret; ret = regulator_enable(chip->reg); if (ret) - goto error_put_reg; + return ret; } mutex_init(&chip->state_lock); @@ -601,12 +538,7 @@ error_unreg_irq: error_disable_reg: if (chip->reg) regulator_disable(chip->reg); -error_put_reg: - if (chip->reg) - regulator_put(chip->reg); -error_free: - iio_device_free(indio_dev); -error_ret: + return ret; } @@ -620,12 +552,8 @@ static int ad7291_remove(struct i2c_client *client) if (client->irq) free_irq(client->irq, indio_dev); - if (chip->reg) { + if (chip->reg) regulator_disable(chip->reg); - regulator_put(chip->reg); - } - - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index 72868ceda360..2083673a79ca 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -85,7 +85,6 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, { int ret; struct ad7606_state *st = iio_priv(indio_dev); - unsigned int scale_uv; switch (m) { case IIO_CHAN_INFO_RAW: @@ -101,11 +100,9 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, *val = (short) ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = (st->range * 1000 * 2) - >> st->chip_info->channels[0].scan_type.realbits; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; + *val = st->range * 2; + *val2 = st->chip_info->channels[0].scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } @@ -425,8 +422,7 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) struct ad7606_state *st = iio_priv(indio_dev); if (iio_buffer_enabled(indio_dev)) { - if (!work_pending(&st->poll_work)) - schedule_work(&st->poll_work); + schedule_work(&st->poll_work); } else { st->done = true; wake_up_interruptible(&st->wq_data_avail); @@ -466,12 +462,11 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, struct ad7606_platform_data *pdata = dev->platform_data; struct ad7606_state *st; int ret; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return ERR_PTR(-ENOMEM); st = iio_priv(indio_dev); @@ -489,11 +484,11 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, st->oversampling = pdata->default_os; } - st->reg = regulator_get(dev, "vcc"); + st->reg = devm_regulator_get(dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ERR_PTR(ret); } st->pdata = pdata; @@ -554,11 +549,6 @@ error_free_gpios: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - iio_device_free(indio_dev); -error_ret: return ERR_PTR(ret); } @@ -570,13 +560,10 @@ int ad7606_remove(struct iio_dev *indio_dev, int irq) ad7606_ring_cleanup(indio_dev); free_irq(irq, indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } ad7606_free_gpios(st); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index 2b25cb07fe41..3bf174cb19b1 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -46,7 +46,6 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) struct ad7606_state *st = container_of(work_s, struct ad7606_state, poll_work); struct iio_dev *indio_dev = iio_priv_to_dev(st); - s64 time_ns; __u8 *buf; int ret; @@ -78,12 +77,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) goto done; } - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - *((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns; - - iio_push_to_buffers(indio_dev, buf); + iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); done: gpio_set_value(st->pdata->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c index e1f88603d7e0..273add3ed63f 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/staging/iio/adc/ad7780.c @@ -90,17 +90,14 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, long m) { struct ad7780_state *st = iio_priv(indio_dev); - unsigned long scale_uv; switch (m) { case IIO_CHAN_INFO_RAW: return ad_sigma_delta_single_conversion(indio_dev, chan, val); case IIO_CHAN_INFO_SCALE: - scale_uv = (st->int_vref_mv * 100000 * st->gain) - >> (chan->scan_type.realbits - 1); - *val = scale_uv / 100000; - *val2 = (scale_uv % 100000) * 10; - return IIO_VAL_INT_PLUS_MICRO; + *val = st->int_vref_mv * st->gain; + *val2 = chan->scan_type.realbits - 1; + return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: *val -= (1 << (chan->scan_type.realbits - 1)); return IIO_VAL_INT; @@ -171,7 +168,7 @@ static int ad7780_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, voltage_uv = 0; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -180,11 +177,11 @@ static int ad7780_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info); - st->reg = regulator_get(&spi->dev, "vcc"); + st->reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; voltage_uv = regulator_get_voltage(st->reg); } @@ -210,8 +207,8 @@ static int ad7780_probe(struct spi_device *spi) if (pdata && gpio_is_valid(pdata->gpio_pdrst)) { - ret = gpio_request_one(pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW, - "AD7780 /PDRST"); + ret = devm_gpio_request_one(&spi->dev, pdata->gpio_pdrst, + GPIOF_OUT_INIT_LOW, "AD7780 /PDRST"); if (ret) { dev_err(&spi->dev, "failed to request GPIO PDRST\n"); goto error_disable_reg; @@ -223,7 +220,7 @@ static int ad7780_probe(struct spi_device *spi) ret = ad_sd_setup_buffer_and_trigger(indio_dev); if (ret) - goto error_free_gpio; + goto error_disable_reg; ret = iio_device_register(indio_dev); if (ret) @@ -233,17 +230,9 @@ static int ad7780_probe(struct spi_device *spi) error_cleanup_buffer_and_trigger: ad_sd_cleanup_buffer_and_trigger(indio_dev); -error_free_gpio: - if (pdata && gpio_is_valid(pdata->gpio_pdrst)) - gpio_free(pdata->gpio_pdrst); error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - - iio_device_free(indio_dev); return ret; } @@ -256,14 +245,8 @@ static int ad7780_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ad_sd_cleanup_buffer_and_trigger(indio_dev); - if (gpio_is_valid(st->powerdown_gpio)) - gpio_free(st->powerdown_gpio); - - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 8470036a3378..9f48e5c74eed 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -356,11 +356,9 @@ static int ad7816_probe(struct spi_device *spi_dev) return -EINVAL; } - indio_dev = iio_device_alloc(sizeof(*chip)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi_dev->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; chip = iio_priv(indio_dev); /* this is only used for device removal purposes */ dev_set_drvdata(&spi_dev->dev, indio_dev); @@ -372,25 +370,28 @@ static int ad7816_probe(struct spi_device *spi_dev) chip->convert_pin = pins[1]; chip->busy_pin = pins[2]; - ret = gpio_request(chip->rdwr_pin, spi_get_device_id(spi_dev)->name); + ret = devm_gpio_request(&spi_dev->dev, chip->rdwr_pin, + spi_get_device_id(spi_dev)->name); if (ret) { dev_err(&spi_dev->dev, "Fail to request rdwr gpio PIN %d.\n", chip->rdwr_pin); - goto error_free_device; + return ret; } gpio_direction_input(chip->rdwr_pin); - ret = gpio_request(chip->convert_pin, spi_get_device_id(spi_dev)->name); + ret = devm_gpio_request(&spi_dev->dev, chip->convert_pin, + spi_get_device_id(spi_dev)->name); if (ret) { dev_err(&spi_dev->dev, "Fail to request convert gpio PIN %d.\n", chip->convert_pin); - goto error_free_gpio_rdwr; + return ret; } gpio_direction_input(chip->convert_pin); - ret = gpio_request(chip->busy_pin, spi_get_device_id(spi_dev)->name); + ret = devm_gpio_request(&spi_dev->dev, chip->busy_pin, + spi_get_device_id(spi_dev)->name); if (ret) { dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n", chip->busy_pin); - goto error_free_gpio_convert; + return ret; } gpio_direction_input(chip->busy_pin); @@ -401,51 +402,31 @@ static int ad7816_probe(struct spi_device *spi_dev) if (spi_dev->irq) { /* Only low trigger is supported in ad7816/7/8 */ - ret = request_threaded_irq(spi_dev->irq, - NULL, - &ad7816_event_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - indio_dev->name, - indio_dev); + ret = devm_request_threaded_irq(&spi_dev->dev, spi_dev->irq, + NULL, + &ad7816_event_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + indio_dev->name, + indio_dev); if (ret) - goto error_free_gpio; + return ret; } ret = iio_device_register(indio_dev); if (ret) - goto error_free_irq; + return ret; dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n", indio_dev->name); return 0; -error_free_irq: - free_irq(spi_dev->irq, indio_dev); -error_free_gpio: - gpio_free(chip->busy_pin); -error_free_gpio_convert: - gpio_free(chip->convert_pin); -error_free_gpio_rdwr: - gpio_free(chip->rdwr_pin); -error_free_device: - iio_device_free(indio_dev); -error_ret: - return ret; } static int ad7816_remove(struct spi_device *spi_dev) { struct iio_dev *indio_dev = dev_get_drvdata(&spi_dev->dev); - struct ad7816_chip_info *chip = iio_priv(indio_dev); iio_device_unregister(indio_dev); - dev_set_drvdata(&spi_dev->dev, NULL); - if (spi_dev->irq) - free_irq(spi_dev->irq, indio_dev); - gpio_free(chip->busy_pin); - gpio_free(chip->convert_pin); - gpio_free(chip->rdwr_pin); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h index b51680c1c331..a591aa6feae1 100644 --- a/drivers/staging/iio/adc/ad799x.h +++ b/drivers/staging/iio/adc/ad799x.h @@ -36,18 +36,10 @@ #define AD7998_ALERT_STAT_REG 0x1 #define AD7998_CONF_REG 0x2 #define AD7998_CYCLE_TMR_REG 0x3 -#define AD7998_DATALOW_CH1_REG 0x4 -#define AD7998_DATAHIGH_CH1_REG 0x5 -#define AD7998_HYST_CH1_REG 0x6 -#define AD7998_DATALOW_CH2_REG 0x7 -#define AD7998_DATAHIGH_CH2_REG 0x8 -#define AD7998_HYST_CH2_REG 0x9 -#define AD7998_DATALOW_CH3_REG 0xA -#define AD7998_DATAHIGH_CH3_REG 0xB -#define AD7998_HYST_CH3_REG 0xC -#define AD7998_DATALOW_CH4_REG 0xD -#define AD7998_DATAHIGH_CH4_REG 0xE -#define AD7998_HYST_CH4_REG 0xF + +#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4) +#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) +#define AD7998_HYST_REG(x) ((x) * 3 + 0x6) #define AD7998_CYC_MASK 0x7 #define AD7998_CYC_DIS 0x0 diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index 2b2049c8bc6b..9428be82b655 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -163,7 +163,6 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, { int ret; struct ad799x_state *st = iio_priv(indio_dev); - unsigned int scale_uv; switch (m) { case IIO_CHAN_INFO_RAW: @@ -180,10 +179,9 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, RES_MASK(chan->scan_type.realbits); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = (st->int_vref_mv * 1000) >> chan->scan_type.realbits; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; + *val = st->int_vref_mv; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; } @@ -254,98 +252,70 @@ error_ret_mutex: } static int ad799x_read_event_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { return 1; } -static const u8 ad799x_threshold_addresses[][2] = { - { AD7998_DATALOW_CH1_REG, AD7998_DATAHIGH_CH1_REG }, - { AD7998_DATALOW_CH2_REG, AD7998_DATAHIGH_CH2_REG }, - { AD7998_DATALOW_CH3_REG, AD7998_DATAHIGH_CH3_REG }, - { AD7998_DATALOW_CH4_REG, AD7998_DATAHIGH_CH4_REG }, -}; +static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan, + enum iio_event_direction dir, + enum iio_event_info info) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + if (dir == IIO_EV_DIR_FALLING) + return AD7998_DATALOW_REG(chan->channel); + else + return AD7998_DATAHIGH_REG(chan->channel); + case IIO_EV_INFO_HYSTERESIS: + return AD7998_HYST_REG(chan->channel); + default: + return -EINVAL; + } + + return 0; +} static int ad799x_write_event_value(struct iio_dev *indio_dev, - u64 event_code, - int val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { int ret; struct ad799x_state *st = iio_priv(indio_dev); - int direction = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_FALLING); - int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code); mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_write16(st, - ad799x_threshold_addresses[number][direction], - val); + ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info), + val); mutex_unlock(&indio_dev->mlock); return ret; } static int ad799x_read_event_value(struct iio_dev *indio_dev, - u64 event_code, - int *val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { int ret; struct ad799x_state *st = iio_priv(indio_dev); - int direction = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_FALLING); - int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code); u16 valin; mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_read16(st, - ad799x_threshold_addresses[number][direction], - &valin); + ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info), + &valin); mutex_unlock(&indio_dev->mlock); if (ret < 0) return ret; *val = valin; - return 0; -} - -static ssize_t ad799x_read_channel_config(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad799x_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - - int ret; - u16 val; - ret = ad799x_i2c_read16(st, this_attr->address, &val); - if (ret) - return ret; - - return sprintf(buf, "%d\n", val); -} - -static ssize_t ad799x_write_channel_config(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad799x_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - - long val; - int ret; - - ret = kstrtol(buf, 10, &val); - if (ret) - return ret; - - mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_write16(st, this_attr->address, val); - mutex_unlock(&indio_dev->mlock); - - return ret ? ret : len; + return IIO_VAL_INT; } static irqreturn_t ad799x_event_handler(int irq, void *private) @@ -383,60 +353,19 @@ done: return IRQ_HANDLED; } -static IIO_DEVICE_ATTR(in_voltage0_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad799x_read_channel_config, - ad799x_write_channel_config, - AD7998_HYST_CH1_REG); - -static IIO_DEVICE_ATTR(in_voltage1_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad799x_read_channel_config, - ad799x_write_channel_config, - AD7998_HYST_CH2_REG); - -static IIO_DEVICE_ATTR(in_voltage2_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad799x_read_channel_config, - ad799x_write_channel_config, - AD7998_HYST_CH3_REG); - -static IIO_DEVICE_ATTR(in_voltage3_thresh_both_hyst_raw, - S_IRUGO | S_IWUSR, - ad799x_read_channel_config, - ad799x_write_channel_config, - AD7998_HYST_CH4_REG); - static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, ad799x_read_frequency, ad799x_write_frequency); static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0"); -static struct attribute *ad7993_4_7_8_event_attributes[] = { - &iio_dev_attr_in_voltage0_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage1_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage2_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage3_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL, -}; - -static struct attribute_group ad7993_4_7_8_event_attrs_group = { - .attrs = ad7993_4_7_8_event_attributes, - .name = "events", -}; - -static struct attribute *ad7992_event_attributes[] = { - &iio_dev_attr_in_voltage0_thresh_both_hyst_raw.dev_attr.attr, - &iio_dev_attr_in_voltage1_thresh_both_hyst_raw.dev_attr.attr, +static struct attribute *ad799x_event_attributes[] = { &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL, }; -static struct attribute_group ad7992_event_attrs_group = { - .attrs = ad7992_event_attributes, +static struct attribute_group ad799x_event_attrs_group = { + .attrs = ad799x_event_attributes, .name = "events", }; @@ -445,29 +374,35 @@ static const struct iio_info ad7991_info = { .driver_module = THIS_MODULE, }; -static const struct iio_info ad7992_info = { - .read_raw = &ad799x_read_raw, - .event_attrs = &ad7992_event_attrs_group, - .read_event_config = &ad799x_read_event_config, - .read_event_value = &ad799x_read_event_value, - .write_event_value = &ad799x_write_event_value, - .driver_module = THIS_MODULE, -}; - static const struct iio_info ad7993_4_7_8_info = { .read_raw = &ad799x_read_raw, - .event_attrs = &ad7993_4_7_8_event_attrs_group, - .read_event_config = &ad799x_read_event_config, - .read_event_value = &ad799x_read_event_value, - .write_event_value = &ad799x_write_event_value, + .event_attrs = &ad799x_event_attrs_group, + .read_event_config_new = &ad799x_read_event_config, + .read_event_value_new = &ad799x_read_event_value, + .write_event_value_new = &ad799x_write_event_value, .driver_module = THIS_MODULE, .update_scan_mode = ad7997_8_update_scan_mode, }; -#define AD799X_EV_MASK (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \ - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) +static const struct iio_event_spec ad799x_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; -#define AD799X_CHANNEL(_index, _realbits, _evmask) { \ +#define _AD799X_CHANNEL(_index, _realbits, _ev_spec, _num_ev_spec) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = (_index), \ @@ -475,16 +410,24 @@ static const struct iio_info ad7993_4_7_8_info = { .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .scan_index = (_index), \ .scan_type = IIO_ST('u', _realbits, 16, 12 - (_realbits)), \ - .event_mask = (_evmask), \ + .event_spec = _ev_spec, \ + .num_event_specs = _num_ev_spec, \ } +#define AD799X_CHANNEL(_index, _realbits) \ + _AD799X_CHANNEL(_index, _realbits, NULL, 0) + +#define AD799X_CHANNEL_WITH_EVENTS(_index, _realbits) \ + _AD799X_CHANNEL(_index, _realbits, ad799x_events, \ + ARRAY_SIZE(ad799x_events)) + static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { [ad7991] = { .channel = { - AD799X_CHANNEL(0, 12, 0), - AD799X_CHANNEL(1, 12, 0), - AD799X_CHANNEL(2, 12, 0), - AD799X_CHANNEL(3, 12, 0), + AD799X_CHANNEL(0, 12), + AD799X_CHANNEL(1, 12), + AD799X_CHANNEL(2, 12), + AD799X_CHANNEL(3, 12), IIO_CHAN_SOFT_TIMESTAMP(4), }, .num_channels = 5, @@ -492,10 +435,10 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7995] = { .channel = { - AD799X_CHANNEL(0, 10, 0), - AD799X_CHANNEL(1, 10, 0), - AD799X_CHANNEL(2, 10, 0), - AD799X_CHANNEL(3, 10, 0), + AD799X_CHANNEL(0, 10), + AD799X_CHANNEL(1, 10), + AD799X_CHANNEL(2, 10), + AD799X_CHANNEL(3, 10), IIO_CHAN_SOFT_TIMESTAMP(4), }, .num_channels = 5, @@ -503,10 +446,10 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7999] = { .channel = { - AD799X_CHANNEL(0, 8, 0), - AD799X_CHANNEL(1, 8, 0), - AD799X_CHANNEL(2, 8, 0), - AD799X_CHANNEL(3, 8, 0), + AD799X_CHANNEL(0, 8), + AD799X_CHANNEL(1, 8), + AD799X_CHANNEL(2, 8), + AD799X_CHANNEL(3, 8), IIO_CHAN_SOFT_TIMESTAMP(4), }, .num_channels = 5, @@ -514,20 +457,20 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7992] = { .channel = { - AD799X_CHANNEL(0, 12, AD799X_EV_MASK), - AD799X_CHANNEL(1, 12, AD799X_EV_MASK), + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), IIO_CHAN_SOFT_TIMESTAMP(3), }, .num_channels = 3, .default_config = AD7998_ALERT_EN, - .info = &ad7992_info, + .info = &ad7993_4_7_8_info, }, [ad7993] = { .channel = { - AD799X_CHANNEL(0, 10, AD799X_EV_MASK), - AD799X_CHANNEL(1, 10, AD799X_EV_MASK), - AD799X_CHANNEL(2, 10, AD799X_EV_MASK), - AD799X_CHANNEL(3, 10, AD799X_EV_MASK), + AD799X_CHANNEL_WITH_EVENTS(0, 10), + AD799X_CHANNEL_WITH_EVENTS(1, 10), + AD799X_CHANNEL_WITH_EVENTS(2, 10), + AD799X_CHANNEL_WITH_EVENTS(3, 10), IIO_CHAN_SOFT_TIMESTAMP(4), }, .num_channels = 5, @@ -536,10 +479,10 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7994] = { .channel = { - AD799X_CHANNEL(0, 12, AD799X_EV_MASK), - AD799X_CHANNEL(1, 12, AD799X_EV_MASK), - AD799X_CHANNEL(2, 12, AD799X_EV_MASK), - AD799X_CHANNEL(3, 12, AD799X_EV_MASK), + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), + AD799X_CHANNEL_WITH_EVENTS(2, 12), + AD799X_CHANNEL_WITH_EVENTS(3, 12), IIO_CHAN_SOFT_TIMESTAMP(4), }, .num_channels = 5, @@ -548,14 +491,14 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7997] = { .channel = { - AD799X_CHANNEL(0, 10, AD799X_EV_MASK), - AD799X_CHANNEL(1, 10, AD799X_EV_MASK), - AD799X_CHANNEL(2, 10, AD799X_EV_MASK), - AD799X_CHANNEL(3, 10, AD799X_EV_MASK), - AD799X_CHANNEL(4, 10, 0), - AD799X_CHANNEL(5, 10, 0), - AD799X_CHANNEL(6, 10, 0), - AD799X_CHANNEL(7, 10, 0), + AD799X_CHANNEL_WITH_EVENTS(0, 10), + AD799X_CHANNEL_WITH_EVENTS(1, 10), + AD799X_CHANNEL_WITH_EVENTS(2, 10), + AD799X_CHANNEL_WITH_EVENTS(3, 10), + AD799X_CHANNEL(4, 10), + AD799X_CHANNEL(5, 10), + AD799X_CHANNEL(6, 10), + AD799X_CHANNEL(7, 10), IIO_CHAN_SOFT_TIMESTAMP(8), }, .num_channels = 9, @@ -564,14 +507,14 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7998] = { .channel = { - AD799X_CHANNEL(0, 12, AD799X_EV_MASK), - AD799X_CHANNEL(1, 12, AD799X_EV_MASK), - AD799X_CHANNEL(2, 12, AD799X_EV_MASK), - AD799X_CHANNEL(3, 12, AD799X_EV_MASK), - AD799X_CHANNEL(4, 12, 0), - AD799X_CHANNEL(5, 12, 0), - AD799X_CHANNEL(6, 12, 0), - AD799X_CHANNEL(7, 12, 0), + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), + AD799X_CHANNEL_WITH_EVENTS(2, 12), + AD799X_CHANNEL_WITH_EVENTS(3, 12), + AD799X_CHANNEL(4, 12), + AD799X_CHANNEL(5, 12), + AD799X_CHANNEL(6, 12), + AD799X_CHANNEL(7, 12), IIO_CHAN_SOFT_TIMESTAMP(8), }, .num_channels = 9, @@ -586,8 +529,9 @@ static int ad799x_probe(struct i2c_client *client, int ret; struct ad799x_platform_data *pdata = client->dev.platform_data; struct ad799x_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -606,11 +550,11 @@ static int ad799x_probe(struct i2c_client *client, st->int_vref_mv = pdata->vref_mv; - st->reg = regulator_get(&client->dev, "vcc"); + st->reg = devm_regulator_get(&client->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; } st->client = client; @@ -650,10 +594,6 @@ error_cleanup_ring: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - iio_device_free(indio_dev); return ret; } @@ -668,12 +608,9 @@ static int ad799x_remove(struct i2c_client *client) free_irq(client->irq, indio_dev); ad799x_ring_cleanup(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } kfree(st->rx_buf); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c index c2ebae12ee19..0ff6c03a483e 100644 --- a/drivers/staging/iio/adc/ad799x_ring.c +++ b/drivers/staging/iio/adc/ad799x_ring.c @@ -35,7 +35,6 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad799x_state *st = iio_priv(indio_dev); - s64 time_ns; int b_sent; u8 cmd; @@ -65,13 +64,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) if (b_sent < 0) goto out; - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - memcpy(st->rx_buf + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - - iio_push_to_buffers(indio_dev, st->rx_buf); + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); out: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index 9a4bb0999b51..ef0a21d8ce15 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -137,43 +137,39 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get platform I/O memory\n"); - retval = -EBUSY; - goto errout1; + return -EBUSY; } - iodev = iio_device_alloc(sizeof(struct lpc32xx_adc_info)); - if (!iodev) { - dev_err(&pdev->dev, "failed allocating iio device\n"); - retval = -ENOMEM; - goto errout1; - } + iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); + if (!iodev) + return -ENOMEM; info = iio_priv(iodev); - info->adc_base = ioremap(res->start, resource_size(res)); + info->adc_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); if (!info->adc_base) { dev_err(&pdev->dev, "failed mapping memory\n"); - retval = -EBUSY; - goto errout2; + return -EBUSY; } - info->clk = clk_get(&pdev->dev, NULL); + info->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed getting clock\n"); - goto errout3; + return PTR_ERR(info->clk); } irq = platform_get_irq(pdev, 0); - if ((irq < 0) || (irq >= NR_IRQS)) { + if (irq <= 0) { dev_err(&pdev->dev, "failed getting interrupt resource\n"); - retval = -EINVAL; - goto errout4; + return -EINVAL; } - retval = request_irq(irq, lpc32xx_adc_isr, 0, MOD_NAME, info); + retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, + MOD_NAME, info); if (retval < 0) { dev_err(&pdev->dev, "failed requesting interrupt\n"); - goto errout4; + return retval; } platform_set_drvdata(pdev, iodev); @@ -189,35 +185,18 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) retval = iio_device_register(iodev); if (retval) - goto errout5; + return retval; dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n", irq); return 0; - -errout5: - free_irq(irq, info); -errout4: - clk_put(info->clk); -errout3: - iounmap(info->adc_base); -errout2: - iio_device_free(iodev); -errout1: - return retval; } static int lpc32xx_adc_remove(struct platform_device *pdev) { struct iio_dev *iodev = platform_get_drvdata(pdev); - struct lpc32xx_adc_info *info = iio_priv(iodev); - int irq = platform_get_irq(pdev, 0); iio_device_unregister(iodev); - free_irq(irq, info); - clk_put(info->clk); - iounmap(info->adc_base); - iio_device_free(iodev); return 0; } diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index a08c1736458b..1bb03e196aa7 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -35,6 +35,7 @@ #include <linux/completion.h> #include <linux/delay.h> #include <linux/input.h> +#include <linux/clk.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -129,11 +130,24 @@ enum mxs_lradc_ts { MXS_LRADC_TOUCHSCREEN_5WIRE, }; +/* + * Touchscreen handling + */ +enum lradc_ts_plate { + LRADC_TOUCH = 0, + LRADC_SAMPLE_X, + LRADC_SAMPLE_Y, + LRADC_SAMPLE_PRESSURE, + LRADC_SAMPLE_VALID, +}; + struct mxs_lradc { struct device *dev; void __iomem *base; int irq[13]; + struct clk *clk; + uint32_t *buffer; struct iio_trigger *trig; @@ -169,32 +183,63 @@ struct mxs_lradc { #define CHAN_MASK_TOUCHSCREEN_4WIRE (0xf << 2) #define CHAN_MASK_TOUCHSCREEN_5WIRE (0x1f << 2) enum mxs_lradc_ts use_touchscreen; - bool stop_touchscreen; bool use_touchbutton; struct input_dev *ts_input; - struct work_struct ts_work; + + enum mxs_lradc_id soc; + enum lradc_ts_plate cur_plate; /* statemachine */ + bool ts_valid; + unsigned ts_x_pos; + unsigned ts_y_pos; + unsigned ts_pressure; + + /* handle touchscreen's physical behaviour */ + /* samples per coordinate */ + unsigned over_sample_cnt; + /* time clocks between samples */ + unsigned over_sample_delay; + /* time in clocks to wait after the plates where switched */ + unsigned settling_delay; }; #define LRADC_CTRL0 0x00 -#define LRADC_CTRL0_TOUCH_DETECT_ENABLE (1 << 23) -#define LRADC_CTRL0_TOUCH_SCREEN_TYPE (1 << 22) -#define LRADC_CTRL0_YNNSW /* YM */ (1 << 21) -#define LRADC_CTRL0_YPNSW /* YP */ (1 << 20) -#define LRADC_CTRL0_YPPSW /* YP */ (1 << 19) -#define LRADC_CTRL0_XNNSW /* XM */ (1 << 18) -#define LRADC_CTRL0_XNPSW /* XM */ (1 << 17) -#define LRADC_CTRL0_XPPSW /* XP */ (1 << 16) -#define LRADC_CTRL0_PLATE_MASK (0x3f << 16) +# define LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE (1 << 23) +# define LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE (1 << 22) +# define LRADC_CTRL0_MX28_YNNSW /* YM */ (1 << 21) +# define LRADC_CTRL0_MX28_YPNSW /* YP */ (1 << 20) +# define LRADC_CTRL0_MX28_YPPSW /* YP */ (1 << 19) +# define LRADC_CTRL0_MX28_XNNSW /* XM */ (1 << 18) +# define LRADC_CTRL0_MX28_XNPSW /* XM */ (1 << 17) +# define LRADC_CTRL0_MX28_XPPSW /* XP */ (1 << 16) + +# define LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE (1 << 20) +# define LRADC_CTRL0_MX23_YM (1 << 19) +# define LRADC_CTRL0_MX23_XM (1 << 18) +# define LRADC_CTRL0_MX23_YP (1 << 17) +# define LRADC_CTRL0_MX23_XP (1 << 16) + +# define LRADC_CTRL0_MX28_PLATE_MASK \ + (LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE | \ + LRADC_CTRL0_MX28_YNNSW | LRADC_CTRL0_MX28_YPNSW | \ + LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_XNNSW | \ + LRADC_CTRL0_MX28_XNPSW | LRADC_CTRL0_MX28_XPPSW) + +# define LRADC_CTRL0_MX23_PLATE_MASK \ + (LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE | \ + LRADC_CTRL0_MX23_YM | LRADC_CTRL0_MX23_XM | \ + LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_XP) #define LRADC_CTRL1 0x10 #define LRADC_CTRL1_TOUCH_DETECT_IRQ_EN (1 << 24) #define LRADC_CTRL1_LRADC_IRQ_EN(n) (1 << ((n) + 16)) -#define LRADC_CTRL1_LRADC_IRQ_EN_MASK (0x1fff << 16) +#define LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK (0x1fff << 16) +#define LRADC_CTRL1_MX23_LRADC_IRQ_EN_MASK (0x01ff << 16) #define LRADC_CTRL1_LRADC_IRQ_EN_OFFSET 16 #define LRADC_CTRL1_TOUCH_DETECT_IRQ (1 << 8) #define LRADC_CTRL1_LRADC_IRQ(n) (1 << (n)) -#define LRADC_CTRL1_LRADC_IRQ_MASK 0x1fff +#define LRADC_CTRL1_MX28_LRADC_IRQ_MASK 0x1fff +#define LRADC_CTRL1_MX23_LRADC_IRQ_MASK 0x01ff #define LRADC_CTRL1_LRADC_IRQ_OFFSET 0 #define LRADC_CTRL2 0x20 @@ -207,19 +252,33 @@ struct mxs_lradc { #define LRADC_CH_ACCUMULATE (1 << 29) #define LRADC_CH_NUM_SAMPLES_MASK (0x1f << 24) #define LRADC_CH_NUM_SAMPLES_OFFSET 24 +#define LRADC_CH_NUM_SAMPLES(x) \ + ((x) << LRADC_CH_NUM_SAMPLES_OFFSET) #define LRADC_CH_VALUE_MASK 0x3ffff #define LRADC_CH_VALUE_OFFSET 0 #define LRADC_DELAY(n) (0xd0 + (0x10 * (n))) #define LRADC_DELAY_TRIGGER_LRADCS_MASK (0xff << 24) #define LRADC_DELAY_TRIGGER_LRADCS_OFFSET 24 +#define LRADC_DELAY_TRIGGER(x) \ + (((x) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) & \ + LRADC_DELAY_TRIGGER_LRADCS_MASK) #define LRADC_DELAY_KICK (1 << 20) #define LRADC_DELAY_TRIGGER_DELAYS_MASK (0xf << 16) #define LRADC_DELAY_TRIGGER_DELAYS_OFFSET 16 +#define LRADC_DELAY_TRIGGER_DELAYS(x) \ + (((x) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) & \ + LRADC_DELAY_TRIGGER_DELAYS_MASK) #define LRADC_DELAY_LOOP_COUNT_MASK (0x1f << 11) #define LRADC_DELAY_LOOP_COUNT_OFFSET 11 +#define LRADC_DELAY_LOOP(x) \ + (((x) << LRADC_DELAY_LOOP_COUNT_OFFSET) & \ + LRADC_DELAY_LOOP_COUNT_MASK) #define LRADC_DELAY_DELAY_MASK 0x7ff #define LRADC_DELAY_DELAY_OFFSET 0 +#define LRADC_DELAY_DELAY(x) \ + (((x) << LRADC_DELAY_DELAY_OFFSET) & \ + LRADC_DELAY_DELAY_MASK) #define LRADC_CTRL4 0x140 #define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4)) @@ -228,6 +287,475 @@ struct mxs_lradc { #define LRADC_RESOLUTION 12 #define LRADC_SINGLE_SAMPLE_MASK ((1 << LRADC_RESOLUTION) - 1) +static void mxs_lradc_reg_set(struct mxs_lradc *lradc, u32 val, u32 reg) +{ + writel(val, lradc->base + reg + STMP_OFFSET_REG_SET); +} + +static void mxs_lradc_reg_clear(struct mxs_lradc *lradc, u32 val, u32 reg) +{ + writel(val, lradc->base + reg + STMP_OFFSET_REG_CLR); +} + +static void mxs_lradc_reg_wrt(struct mxs_lradc *lradc, u32 val, u32 reg) +{ + writel(val, lradc->base + reg); +} + +static u32 mxs_lradc_plate_mask(struct mxs_lradc *lradc) +{ + if (lradc->soc == IMX23_LRADC) + return LRADC_CTRL0_MX23_PLATE_MASK; + else + return LRADC_CTRL0_MX28_PLATE_MASK; +} + +static u32 mxs_lradc_irq_en_mask(struct mxs_lradc *lradc) +{ + if (lradc->soc == IMX23_LRADC) + return LRADC_CTRL1_MX23_LRADC_IRQ_EN_MASK; + else + return LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK; +} + +static u32 mxs_lradc_irq_mask(struct mxs_lradc *lradc) +{ + if (lradc->soc == IMX23_LRADC) + return LRADC_CTRL1_MX23_LRADC_IRQ_MASK; + else + return LRADC_CTRL1_MX28_LRADC_IRQ_MASK; +} + +static u32 mxs_lradc_touch_detect_bit(struct mxs_lradc *lradc) +{ + if (lradc->soc == IMX23_LRADC) + return LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE; + else + return LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE; +} + +static u32 mxs_lradc_drive_x_plate(struct mxs_lradc *lradc) +{ + if (lradc->soc == IMX23_LRADC) + return LRADC_CTRL0_MX23_XP | LRADC_CTRL0_MX23_XM; + else + return LRADC_CTRL0_MX28_XPPSW | LRADC_CTRL0_MX28_XNNSW; +} + +static u32 mxs_lradc_drive_y_plate(struct mxs_lradc *lradc) +{ + if (lradc->soc == IMX23_LRADC) + return LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_YM; + else + return LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_YNNSW; +} + +static u32 mxs_lradc_drive_pressure(struct mxs_lradc *lradc) +{ + if (lradc->soc == IMX23_LRADC) + return LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_XM; + else + return LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_XNNSW; +} + +static bool mxs_lradc_check_touch_event(struct mxs_lradc *lradc) +{ + return !!(readl(lradc->base + LRADC_STATUS) & + LRADC_STATUS_TOUCH_DETECT_RAW); +} + +static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch) +{ + /* + * prepare for oversampling conversion + * + * from the datasheet: + * "The ACCUMULATE bit in the appropriate channel register + * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; + * otherwise, the IRQs will not fire." + */ + mxs_lradc_reg_wrt(lradc, LRADC_CH_ACCUMULATE | + LRADC_CH_NUM_SAMPLES(lradc->over_sample_cnt - 1), + LRADC_CH(ch)); + + /* from the datasheet: + * "Software must clear this register in preparation for a + * multi-cycle accumulation. + */ + mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch)); + + /* prepare the delay/loop unit according to the oversampling count */ + mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << ch) | + LRADC_DELAY_TRIGGER_DELAYS(0) | + LRADC_DELAY_LOOP(lradc->over_sample_cnt - 1) | + LRADC_DELAY_DELAY(lradc->over_sample_delay - 1), + LRADC_DELAY(3)); + + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) | + LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) | + LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); + + /* wake us again, when the complete conversion is done */ + mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch), LRADC_CTRL1); + /* + * after changing the touchscreen plates setting + * the signals need some initial time to settle. Start the + * SoC's delay unit and start the conversion later + * and automatically. + */ + mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(0) | /* don't trigger ADC */ + LRADC_DELAY_TRIGGER_DELAYS(1 << 3) | /* trigger DELAY unit#3 */ + LRADC_DELAY_KICK | + LRADC_DELAY_DELAY(lradc->settling_delay), + LRADC_DELAY(2)); +} + +/* + * Pressure detection is special: + * We want to do both required measurements for the pressure detection in + * one turn. Use the hardware features to chain both conversions and let the + * hardware report one interrupt if both conversions are done + */ +static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1, + unsigned ch2) +{ + u32 reg; + + /* + * prepare for oversampling conversion + * + * from the datasheet: + * "The ACCUMULATE bit in the appropriate channel register + * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0; + * otherwise, the IRQs will not fire." + */ + reg = LRADC_CH_ACCUMULATE | + LRADC_CH_NUM_SAMPLES(lradc->over_sample_cnt - 1); + mxs_lradc_reg_wrt(lradc, reg, LRADC_CH(ch1)); + mxs_lradc_reg_wrt(lradc, reg, LRADC_CH(ch2)); + + /* from the datasheet: + * "Software must clear this register in preparation for a + * multi-cycle accumulation. + */ + mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch1)); + mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch2)); + + /* prepare the delay/loop unit according to the oversampling count */ + mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << ch1) | + LRADC_DELAY_TRIGGER(1 << ch2) | /* start both channels */ + LRADC_DELAY_TRIGGER_DELAYS(0) | + LRADC_DELAY_LOOP(lradc->over_sample_cnt - 1) | + LRADC_DELAY_DELAY(lradc->over_sample_delay - 1), + LRADC_DELAY(3)); + + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) | + LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) | + LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); + + /* wake us again, when the conversions are done */ + mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch2), LRADC_CTRL1); + /* + * after changing the touchscreen plates setting + * the signals need some initial time to settle. Start the + * SoC's delay unit and start the conversion later + * and automatically. + */ + mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(0) | /* don't trigger ADC */ + LRADC_DELAY_TRIGGER_DELAYS(1 << 3) | /* trigger DELAY unit#3 */ + LRADC_DELAY_KICK | + LRADC_DELAY_DELAY(lradc->settling_delay), LRADC_DELAY(2)); +} + +static unsigned mxs_lradc_read_raw_channel(struct mxs_lradc *lradc, + unsigned channel) +{ + u32 reg; + unsigned num_samples, val; + + reg = readl(lradc->base + LRADC_CH(channel)); + if (reg & LRADC_CH_ACCUMULATE) + num_samples = lradc->over_sample_cnt; + else + num_samples = 1; + + val = (reg & LRADC_CH_VALUE_MASK) >> LRADC_CH_VALUE_OFFSET; + return val / num_samples; +} + +static unsigned mxs_lradc_read_ts_pressure(struct mxs_lradc *lradc, + unsigned ch1, unsigned ch2) +{ + u32 reg, mask; + unsigned pressure, m1, m2; + + mask = LRADC_CTRL1_LRADC_IRQ(ch1) | LRADC_CTRL1_LRADC_IRQ(ch2); + reg = readl(lradc->base + LRADC_CTRL1) & mask; + + while (reg != mask) { + reg = readl(lradc->base + LRADC_CTRL1) & mask; + dev_dbg(lradc->dev, "One channel is still busy: %X\n", reg); + } + + m1 = mxs_lradc_read_raw_channel(lradc, ch1); + m2 = mxs_lradc_read_raw_channel(lradc, ch2); + + if (m2 == 0) { + dev_warn(lradc->dev, "Cannot calculate pressure\n"); + return 1 << (LRADC_RESOLUTION - 1); + } + + /* simply scale the value from 0 ... max ADC resolution */ + pressure = m1; + pressure *= (1 << LRADC_RESOLUTION); + pressure /= m2; + + dev_dbg(lradc->dev, "Pressure = %u\n", pressure); + return pressure; +} + +#define TS_CH_XP 2 +#define TS_CH_YP 3 +#define TS_CH_XM 4 +#define TS_CH_YM 5 + +static int mxs_lradc_read_ts_channel(struct mxs_lradc *lradc) +{ + u32 reg; + int val; + + reg = readl(lradc->base + LRADC_CTRL1); + + /* only channels 3 to 5 are of interest here */ + if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YP)) { + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YP) | + LRADC_CTRL1_LRADC_IRQ(TS_CH_YP), LRADC_CTRL1); + val = mxs_lradc_read_raw_channel(lradc, TS_CH_YP); + } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_XM)) { + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_XM) | + LRADC_CTRL1_LRADC_IRQ(TS_CH_XM), LRADC_CTRL1); + val = mxs_lradc_read_raw_channel(lradc, TS_CH_XM); + } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YM)) { + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YM) | + LRADC_CTRL1_LRADC_IRQ(TS_CH_YM), LRADC_CTRL1); + val = mxs_lradc_read_raw_channel(lradc, TS_CH_YM); + } else { + return -EIO; + } + + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2)); + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3)); + + return val; +} + +/* + * YP(open)--+-------------+ + * | |--+ + * | | | + * YM(-)--+-------------+ | + * +--------------+ + * | | + * XP(weak+) XM(open) + * + * "weak+" means 200k Ohm VDDIO + * (-) means GND + */ +static void mxs_lradc_setup_touch_detection(struct mxs_lradc *lradc) +{ + /* + * In order to detect a touch event the 'touch detect enable' bit + * enables: + * - a weak pullup to the X+ connector + * - a strong ground at the Y- connector + */ + mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0); + mxs_lradc_reg_set(lradc, mxs_lradc_touch_detect_bit(lradc), + LRADC_CTRL0); +} + +/* + * YP(meas)--+-------------+ + * | |--+ + * | | | + * YM(open)--+-------------+ | + * +--------------+ + * | | + * XP(+) XM(-) + * + * (+) means here 1.85 V + * (-) means here GND + */ +static void mxs_lradc_prepare_x_pos(struct mxs_lradc *lradc) +{ + mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0); + mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0); + + lradc->cur_plate = LRADC_SAMPLE_X; + mxs_lradc_setup_ts_channel(lradc, TS_CH_YP); +} + +/* + * YP(+)--+-------------+ + * | |--+ + * | | | + * YM(-)--+-------------+ | + * +--------------+ + * | | + * XP(open) XM(meas) + * + * (+) means here 1.85 V + * (-) means here GND + */ +static void mxs_lradc_prepare_y_pos(struct mxs_lradc *lradc) +{ + mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0); + mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0); + + lradc->cur_plate = LRADC_SAMPLE_Y; + mxs_lradc_setup_ts_channel(lradc, TS_CH_XM); +} + +/* + * YP(+)--+-------------+ + * | |--+ + * | | | + * YM(meas)--+-------------+ | + * +--------------+ + * | | + * XP(meas) XM(-) + * + * (+) means here 1.85 V + * (-) means here GND + */ +static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc) +{ + mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0); + mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0); + + lradc->cur_plate = LRADC_SAMPLE_PRESSURE; + mxs_lradc_setup_ts_pressure(lradc, TS_CH_XP, TS_CH_YM); +} + +static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc) +{ + mxs_lradc_setup_touch_detection(lradc); + + lradc->cur_plate = LRADC_TOUCH; + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ | + LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); + mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); +} + +static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc) +{ + input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos); + input_report_abs(lradc->ts_input, ABS_Y, lradc->ts_y_pos); + input_report_abs(lradc->ts_input, ABS_PRESSURE, lradc->ts_pressure); + input_report_key(lradc->ts_input, BTN_TOUCH, 1); + input_sync(lradc->ts_input); +} + +static void mxs_lradc_complete_touch_event(struct mxs_lradc *lradc) +{ + mxs_lradc_setup_touch_detection(lradc); + lradc->cur_plate = LRADC_SAMPLE_VALID; + /* + * start a dummy conversion to burn time to settle the signals + * note: we are not interested in the conversion's value + */ + mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(5)); + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); + mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(5), LRADC_CTRL1); + mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << 5) | + LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */ + LRADC_DELAY(2)); +} + +/* + * in order to avoid false measurements, report only samples where + * the surface is still touched after the position measurement + */ +static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid) +{ + /* if it is still touched, report the sample */ + if (valid && mxs_lradc_check_touch_event(lradc)) { + lradc->ts_valid = true; + mxs_lradc_report_ts_event(lradc); + } + + /* if it is even still touched, continue with the next measurement */ + if (mxs_lradc_check_touch_event(lradc)) { + mxs_lradc_prepare_y_pos(lradc); + return; + } + + if (lradc->ts_valid) { + /* signal the release */ + lradc->ts_valid = false; + input_report_key(lradc->ts_input, BTN_TOUCH, 0); + input_sync(lradc->ts_input); + } + + /* if it is released, wait for the next touch via IRQ */ + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1); + mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); +} + +/* touchscreen's state machine */ +static void mxs_lradc_handle_touch(struct mxs_lradc *lradc) +{ + int val; + + switch (lradc->cur_plate) { + case LRADC_TOUCH: + /* + * start with the Y-pos, because it uses nearly the same plate + * settings like the touch detection + */ + if (mxs_lradc_check_touch_event(lradc)) { + mxs_lradc_reg_clear(lradc, + LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, + LRADC_CTRL1); + mxs_lradc_prepare_y_pos(lradc); + } + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, + LRADC_CTRL1); + return; + + case LRADC_SAMPLE_Y: + val = mxs_lradc_read_ts_channel(lradc); + if (val < 0) { + mxs_lradc_enable_touch_detection(lradc); /* re-start */ + return; + } + lradc->ts_y_pos = val; + mxs_lradc_prepare_x_pos(lradc); + return; + + case LRADC_SAMPLE_X: + val = mxs_lradc_read_ts_channel(lradc); + if (val < 0) { + mxs_lradc_enable_touch_detection(lradc); /* re-start */ + return; + } + lradc->ts_x_pos = val; + mxs_lradc_prepare_pressure(lradc); + return; + + case LRADC_SAMPLE_PRESSURE: + lradc->ts_pressure = + mxs_lradc_read_ts_pressure(lradc, TS_CH_XP, TS_CH_YM); + mxs_lradc_complete_touch_event(lradc); + return; + + case LRADC_SAMPLE_VALID: + val = mxs_lradc_read_ts_channel(lradc); /* ignore the value */ + mxs_lradc_finish_touch_event(lradc, 1); + break; + } +} + /* * Raw I/O operations */ @@ -262,21 +790,20 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, * Virtual channel 0 is always used here as the others are always not * used if doing raw sampling. */ - writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); - writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + if (lradc->soc == IMX28_LRADC) + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK, + LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); /* Clean the slot's previous content, then set new one. */ - writel(LRADC_CTRL4_LRADCSELECT_MASK(0), - lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR); - writel(chan->channel, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET); + mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(0), LRADC_CTRL4); + mxs_lradc_reg_set(lradc, chan->channel, LRADC_CTRL4); - writel(0, lradc->base + LRADC_CH(0)); + mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(0)); /* Enable the IRQ and start sampling the channel. */ - writel(LRADC_CTRL1_LRADC_IRQ_EN(0), - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); - writel(1 << 0, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0), LRADC_CTRL1); + mxs_lradc_reg_set(lradc, 1 << 0, LRADC_CTRL0); /* Wait for completion on the channel, 1 second max. */ ret = wait_for_completion_killable_timeout(&lradc->completion, HZ); @@ -290,8 +817,7 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, ret = IIO_VAL_INT; err: - writel(LRADC_CTRL1_LRADC_IRQ_EN(0), - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0), LRADC_CTRL1); mutex_unlock(&lradc->lock); @@ -303,220 +829,33 @@ static const struct iio_info mxs_lradc_iio_info = { .read_raw = mxs_lradc_read_raw, }; -/* - * Touchscreen handling - */ -enum lradc_ts_plate { - LRADC_SAMPLE_X, - LRADC_SAMPLE_Y, - LRADC_SAMPLE_PRESSURE, -}; - -static int mxs_lradc_ts_touched(struct mxs_lradc *lradc) -{ - uint32_t reg; - - /* Enable touch detection. */ - writel(LRADC_CTRL0_PLATE_MASK, - lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); - writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE, - lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); - - msleep(LRADC_TS_SAMPLE_DELAY_MS); - - reg = readl(lradc->base + LRADC_STATUS); - - return reg & LRADC_STATUS_TOUCH_DETECT_RAW; -} - -static int32_t mxs_lradc_ts_sample(struct mxs_lradc *lradc, - enum lradc_ts_plate plate, int change) -{ - unsigned long delay, jiff; - uint32_t reg, ctrl0 = 0, chan = 0; - /* The touchscreen always uses CTRL4 slot #7. */ - const uint8_t slot = 7; - uint32_t val; - - /* - * There are three correct configurations of the controller sampling - * the touchscreen, each of these configuration provides different - * information from the touchscreen. - * - * The following table describes the sampling configurations: - * +-------------+-------+-------+-------+ - * | Wire \ Axis | X | Y | Z | - * +---------------------+-------+-------+ - * | X+ (CH2) | HI | TS | TS | - * +-------------+-------+-------+-------+ - * | X- (CH4) | LO | SH | HI | - * +-------------+-------+-------+-------+ - * | Y+ (CH3) | SH | HI | HI | - * +-------------+-------+-------+-------+ - * | Y- (CH5) | TS | LO | SH | - * +-------------+-------+-------+-------+ - * - * HI ... strong '1' ; LO ... strong '0' - * SH ... sample here ; TS ... tri-state - * - * There are a few other ways of obtaining the Z coordinate - * (aka. pressure), but the one in the table seems to be the - * most reliable one. - */ - switch (plate) { - case LRADC_SAMPLE_X: - ctrl0 = LRADC_CTRL0_XPPSW | LRADC_CTRL0_XNNSW; - chan = 3; - break; - case LRADC_SAMPLE_Y: - ctrl0 = LRADC_CTRL0_YPPSW | LRADC_CTRL0_YNNSW; - chan = 4; - break; - case LRADC_SAMPLE_PRESSURE: - ctrl0 = LRADC_CTRL0_YPPSW | LRADC_CTRL0_XNNSW; - chan = 5; - break; - } - - if (change) { - writel(LRADC_CTRL0_PLATE_MASK, - lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); - writel(ctrl0, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); - - writel(LRADC_CTRL4_LRADCSELECT_MASK(slot), - lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR); - writel(chan << LRADC_CTRL4_LRADCSELECT_OFFSET(slot), - lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET); - } - - writel(0xffffffff, lradc->base + LRADC_CH(slot) + STMP_OFFSET_REG_CLR); - writel(1 << slot, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); - - delay = jiffies + msecs_to_jiffies(LRADC_TS_SAMPLE_DELAY_MS); - do { - jiff = jiffies; - reg = readl_relaxed(lradc->base + LRADC_CTRL1); - if (reg & LRADC_CTRL1_LRADC_IRQ(slot)) - break; - } while (time_before(jiff, delay)); - - writel(LRADC_CTRL1_LRADC_IRQ(slot), - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); - - if (time_after_eq(jiff, delay)) - return -ETIMEDOUT; - - val = readl(lradc->base + LRADC_CH(slot)); - val &= LRADC_CH_VALUE_MASK; - - return val; -} - -static int32_t mxs_lradc_ts_sample_filter(struct mxs_lradc *lradc, - enum lradc_ts_plate plate) -{ - int32_t val, tot = 0; - int i; - - val = mxs_lradc_ts_sample(lradc, plate, 1); - - /* Delay a bit so the touchscreen is stable. */ - mdelay(2); - - for (i = 0; i < LRADC_TS_SAMPLE_AMOUNT; i++) { - val = mxs_lradc_ts_sample(lradc, plate, 0); - tot += val; - } - - return tot / LRADC_TS_SAMPLE_AMOUNT; -} - -static void mxs_lradc_ts_work(struct work_struct *ts_work) -{ - struct mxs_lradc *lradc = container_of(ts_work, - struct mxs_lradc, ts_work); - int val_x, val_y, val_p; - bool valid = false; - - while (mxs_lradc_ts_touched(lradc)) { - /* Disable touch detector so we can sample the touchscreen. */ - writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE, - lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); - - if (likely(valid)) { - input_report_abs(lradc->ts_input, ABS_X, val_x); - input_report_abs(lradc->ts_input, ABS_Y, val_y); - input_report_abs(lradc->ts_input, ABS_PRESSURE, val_p); - input_report_key(lradc->ts_input, BTN_TOUCH, 1); - input_sync(lradc->ts_input); - } - - valid = false; - - val_x = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_X); - if (val_x < 0) - continue; - val_y = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_Y); - if (val_y < 0) - continue; - val_p = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_PRESSURE); - if (val_p < 0) - continue; - - valid = true; - } - - input_report_abs(lradc->ts_input, ABS_PRESSURE, 0); - input_report_key(lradc->ts_input, BTN_TOUCH, 0); - input_sync(lradc->ts_input); - - /* Do not restart the TS IRQ if the driver is shutting down. */ - if (lradc->stop_touchscreen) - return; - - /* Restart the touchscreen interrupts. */ - writel(LRADC_CTRL1_TOUCH_DETECT_IRQ, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); - writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); -} - static int mxs_lradc_ts_open(struct input_dev *dev) { struct mxs_lradc *lradc = input_get_drvdata(dev); - /* The touchscreen is starting. */ - lradc->stop_touchscreen = false; - /* Enable the touch-detect circuitry. */ - writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE, - lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); - - /* Enable the touch-detect IRQ. */ - writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); + mxs_lradc_enable_touch_detection(lradc); return 0; } -static void mxs_lradc_ts_close(struct input_dev *dev) +static void mxs_lradc_disable_ts(struct mxs_lradc *lradc) { - struct mxs_lradc *lradc = input_get_drvdata(dev); - - /* Indicate the touchscreen is stopping. */ - lradc->stop_touchscreen = true; - mb(); + /* stop all interrupts from firing */ + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN | + LRADC_CTRL1_LRADC_IRQ_EN(2) | LRADC_CTRL1_LRADC_IRQ_EN(3) | + LRADC_CTRL1_LRADC_IRQ_EN(4) | LRADC_CTRL1_LRADC_IRQ_EN(5), + LRADC_CTRL1); - /* Wait until touchscreen thread finishes any possible remnants. */ - cancel_work_sync(&lradc->ts_work); + /* Power-down touchscreen touch-detect circuitry. */ + mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0); +} - /* Disable touchscreen touch-detect IRQ. */ - writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); +static void mxs_lradc_ts_close(struct input_dev *dev) +{ + struct mxs_lradc *lradc = input_get_drvdata(dev); - /* Power-down touchscreen touch-detect circuitry. */ - writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE, - lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + mxs_lradc_disable_ts(lradc); } static int mxs_lradc_ts_register(struct mxs_lradc *lradc) @@ -562,8 +901,7 @@ static void mxs_lradc_ts_unregister(struct mxs_lradc *lradc) if (!lradc->use_touchscreen) return; - cancel_work_sync(&lradc->ts_work); - + mxs_lradc_disable_ts(lradc); input_unregister_device(lradc->ts_input); } @@ -576,31 +914,24 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data) struct mxs_lradc *lradc = iio_priv(iio); unsigned long reg = readl(lradc->base + LRADC_CTRL1); const uint32_t ts_irq_mask = - LRADC_CTRL1_TOUCH_DETECT_IRQ_EN | - LRADC_CTRL1_TOUCH_DETECT_IRQ; + LRADC_CTRL1_TOUCH_DETECT_IRQ | + LRADC_CTRL1_LRADC_IRQ(2) | + LRADC_CTRL1_LRADC_IRQ(3) | + LRADC_CTRL1_LRADC_IRQ(4) | + LRADC_CTRL1_LRADC_IRQ(5); - if (!(reg & LRADC_CTRL1_LRADC_IRQ_MASK)) + if (!(reg & mxs_lradc_irq_mask(lradc))) return IRQ_NONE; - /* - * Touchscreen IRQ handling code has priority and therefore - * is placed here. In case touchscreen IRQ arrives, disable - * it ASAP - */ - if (reg & LRADC_CTRL1_TOUCH_DETECT_IRQ) { - writel(ts_irq_mask, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); - if (!lradc->stop_touchscreen) - schedule_work(&lradc->ts_work); - } + if (lradc->use_touchscreen && (reg & ts_irq_mask)) + mxs_lradc_handle_touch(lradc); if (iio_buffer_enabled(iio)) iio_trigger_poll(iio->trig, iio_get_time_ns()); else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) complete(&lradc->completion); - writel(reg & LRADC_CTRL1_LRADC_IRQ_MASK, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc), LRADC_CTRL1); return IRQ_HANDLED; } @@ -619,19 +950,13 @@ static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p) for_each_set_bit(i, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) { lradc->buffer[j] = readl(lradc->base + LRADC_CH(j)); - writel(chan_value, lradc->base + LRADC_CH(j)); + mxs_lradc_reg_wrt(lradc, chan_value, LRADC_CH(j)); lradc->buffer[j] &= LRADC_CH_VALUE_MASK; lradc->buffer[j] /= LRADC_DELAY_TIMER_LOOP; j++; } - if (iio->scan_timestamp) { - s64 *timestamp = (s64 *)((u8 *)lradc->buffer + - ALIGN(j, sizeof(s64))); - *timestamp = pf->timestamp; - } - - iio_push_to_buffers(iio, (u8 *)lradc->buffer); + iio_push_to_buffers_with_timestamp(iio, lradc->buffer, pf->timestamp); iio_trigger_notify_done(iio->trig); @@ -644,7 +969,7 @@ static int mxs_lradc_configure_trigger(struct iio_trigger *trig, bool state) struct mxs_lradc *lradc = iio_priv(iio); const uint32_t st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR; - writel(LRADC_DELAY_KICK, lradc->base + LRADC_DELAY(0) + st); + mxs_lradc_reg_wrt(lradc, LRADC_DELAY_KICK, LRADC_DELAY(0) + st); return 0; } @@ -716,38 +1041,30 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) goto err_mem; } - ret = iio_sw_buffer_preenable(iio); - if (ret < 0) - goto err_buf; - - writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); - writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + if (lradc->soc == IMX28_LRADC) + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK, + LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) { ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs); ctrl4_clr |= LRADC_CTRL4_LRADCSELECT_MASK(ofs); ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs); - writel(chan_value, lradc->base + LRADC_CH(ofs)); + mxs_lradc_reg_wrt(lradc, chan_value, LRADC_CH(ofs)); bitmap_set(&enable, ofs, 1); ofs++; } - writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK, - lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR); - - writel(ctrl4_clr, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR); - writel(ctrl4_set, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET); - - writel(ctrl1_irq, lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); - - writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET, - lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_SET); + mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK | + LRADC_DELAY_KICK, LRADC_DELAY(0)); + mxs_lradc_reg_clear(lradc, ctrl4_clr, LRADC_CTRL4); + mxs_lradc_reg_set(lradc, ctrl4_set, LRADC_CTRL4); + mxs_lradc_reg_set(lradc, ctrl1_irq, LRADC_CTRL1); + mxs_lradc_reg_set(lradc, enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET, + LRADC_DELAY(0)); return 0; -err_buf: - kfree(lradc->buffer); err_mem: mutex_unlock(&lradc->lock); return ret; @@ -757,12 +1074,13 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio) { struct mxs_lradc *lradc = iio_priv(iio); - writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK, - lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR); + mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK | + LRADC_DELAY_KICK, LRADC_DELAY(0)); - writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); - writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); + if (lradc->soc == IMX28_LRADC) + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK, + LRADC_CTRL1); kfree(lradc->buffer); mutex_unlock(&lradc->lock); @@ -857,24 +1175,25 @@ static int mxs_lradc_hw_init(struct mxs_lradc *lradc) return ret; /* Configure DELAY CHANNEL 0 for generic ADC sampling. */ - writel(adc_cfg, lradc->base + LRADC_DELAY(0)); + mxs_lradc_reg_wrt(lradc, adc_cfg, LRADC_DELAY(0)); /* Disable remaining DELAY CHANNELs */ - writel(0, lradc->base + LRADC_DELAY(1)); - writel(0, lradc->base + LRADC_DELAY(2)); - writel(0, lradc->base + LRADC_DELAY(3)); + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(1)); + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2)); + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3)); /* Configure the touchscreen type */ - writel(LRADC_CTRL0_TOUCH_SCREEN_TYPE, - lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + if (lradc->soc == IMX28_LRADC) { + mxs_lradc_reg_clear(lradc, LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE, + LRADC_CTRL0); - if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE) { - writel(LRADC_CTRL0_TOUCH_SCREEN_TYPE, - lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE) + mxs_lradc_reg_set(lradc, LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE, + LRADC_CTRL0); } /* Start internal temperature sensing. */ - writel(0, lradc->base + LRADC_CTRL2); + mxs_lradc_reg_wrt(lradc, 0, LRADC_CTRL2); return 0; } @@ -883,11 +1202,10 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc) { int i; - writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, - lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + mxs_lradc_reg_clear(lradc, mxs_lradc_irq_en_mask(lradc), LRADC_CTRL1); for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++) - writel(0, lradc->base + LRADC_DELAY(i)); + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(i)); } static const struct of_device_id mxs_lradc_dt_ids[] = { @@ -897,6 +1215,52 @@ static const struct of_device_id mxs_lradc_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids); +static int mxs_lradc_probe_touchscreen(struct mxs_lradc *lradc, + struct device_node *lradc_node) +{ + int ret; + u32 ts_wires = 0, adapt; + + ret = of_property_read_u32(lradc_node, "fsl,lradc-touchscreen-wires", + &ts_wires); + if (ret) + return -ENODEV; /* touchscreen feature disabled */ + + switch (ts_wires) { + case 4: + lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_4WIRE; + break; + case 5: + if (lradc->soc == IMX28_LRADC) { + lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_5WIRE; + break; + } + /* fall through an error message for i.MX23 */ + default: + dev_err(lradc->dev, + "Unsupported number of touchscreen wires (%d)\n", + ts_wires); + return -EINVAL; + } + + lradc->over_sample_cnt = 4; + ret = of_property_read_u32(lradc_node, "fsl,ave-ctrl", &adapt); + if (ret == 0) + lradc->over_sample_cnt = adapt; + + lradc->over_sample_delay = 2; + ret = of_property_read_u32(lradc_node, "fsl,ave-delay", &adapt); + if (ret == 0) + lradc->over_sample_delay = adapt; + + lradc->settling_delay = 10; + ret = of_property_read_u32(lradc_node, "fsl,settling", &adapt); + if (ret == 0) + lradc->settling_delay = adapt; + + return 0; +} + static int mxs_lradc_probe(struct platform_device *pdev) { const struct of_device_id *of_id = @@ -908,8 +1272,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) struct mxs_lradc *lradc; struct iio_dev *iio; struct resource *iores; - uint32_t ts_wires = 0; - int ret = 0; + int ret = 0, touch_ret; int i; /* Allocate the IIO device. */ @@ -920,6 +1283,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) } lradc = iio_priv(iio); + lradc->soc = (enum mxs_lradc_id)of_id->data; /* Grab the memory area */ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -928,20 +1292,18 @@ static int mxs_lradc_probe(struct platform_device *pdev) if (IS_ERR(lradc->base)) return PTR_ERR(lradc->base); - INIT_WORK(&lradc->ts_work, mxs_lradc_ts_work); + lradc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(lradc->clk)) { + dev_err(dev, "Failed to get the delay unit clock\n"); + return PTR_ERR(lradc->clk); + } + ret = clk_prepare_enable(lradc->clk); + if (ret != 0) { + dev_err(dev, "Failed to enable the delay unit clock\n"); + return ret; + } - /* Check if touchscreen is enabled in DT. */ - ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires", - &ts_wires); - if (ret) - dev_info(dev, "Touchscreen not enabled.\n"); - else if (ts_wires == 4) - lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_4WIRE; - else if (ts_wires == 5) - lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_5WIRE; - else - dev_warn(dev, "Unsupported number of touchscreen wires (%d)\n", - ts_wires); + touch_ret = mxs_lradc_probe_touchscreen(lradc, node); /* Grab all IRQ sources */ for (i = 0; i < of_cfg->irq_count; i++) { @@ -985,9 +1347,11 @@ static int mxs_lradc_probe(struct platform_device *pdev) goto err_dev; /* Register the touchscreen input device. */ - ret = mxs_lradc_ts_register(lradc); - if (ret) - goto err_dev; + if (touch_ret == 0) { + ret = mxs_lradc_ts_register(lradc); + if (ret) + goto err_ts_register; + } /* Register IIO device. */ ret = iio_device_register(iio); @@ -1000,6 +1364,8 @@ static int mxs_lradc_probe(struct platform_device *pdev) err_ts: mxs_lradc_ts_unregister(lradc); +err_ts_register: + mxs_lradc_hw_stop(lradc); err_dev: mxs_lradc_trigger_remove(iio); err_trig: @@ -1012,14 +1378,13 @@ static int mxs_lradc_remove(struct platform_device *pdev) struct iio_dev *iio = platform_get_drvdata(pdev); struct mxs_lradc *lradc = iio_priv(iio); + iio_device_unregister(iio); mxs_lradc_ts_unregister(lradc); - mxs_lradc_hw_stop(lradc); - - iio_device_unregister(iio); - iio_triggered_buffer_cleanup(iio); mxs_lradc_trigger_remove(iio); + iio_triggered_buffer_cleanup(iio); + clk_disable_unprepare(lradc->clk); return 0; } @@ -1038,3 +1403,4 @@ module_platform_driver(mxs_lradc_driver); MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 20f2d555e7cd..970d9edc73b6 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -146,7 +146,6 @@ static int spear_read_raw(struct iio_dev *indio_dev, long mask) { struct spear_adc_info *info = iio_priv(indio_dev); - u32 scale_mv; u32 status; switch (mask) { @@ -168,10 +167,9 @@ static int spear_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_mv = (info->vref_external * 1000) >> DATA_BITS; - *val = scale_mv / 1000; - *val2 = (scale_mv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; + *val = info->vref_external; + *val2 = DATA_BITS; + return IIO_VAL_FRACTIONAL_LOG2; } return -EINVAL; @@ -320,7 +318,7 @@ static int spear_adc_probe(struct platform_device *pdev) return -ENOMEM; } info->adc_base_spear3xx = - (struct adc_regs_spear3xx *)info->adc_base_spear6xx; + (struct adc_regs_spear3xx __iomem *)info->adc_base_spear6xx; info->clk = clk_get(dev, NULL); if (IS_ERR(info->clk)) { @@ -335,7 +333,7 @@ static int spear_adc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if ((irq < 0) || (irq >= NR_IRQS)) { + if (irq <= 0) { dev_err(dev, "failed getting interrupt resource\n"); ret = -EINVAL; goto errout3; diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c index ce7d91cb331c..0feea5541d02 100644 --- a/drivers/staging/iio/addac/adt7316-i2c.c +++ b/drivers/staging/iio/addac/adt7316-i2c.c @@ -138,6 +138,5 @@ static struct i2c_driver adt7316_driver = { module_i2c_driver(adt7316_driver); MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); -MODULE_DESCRIPTION("I2C bus driver for Analog Devices ADT7316/7/9 and" - "ADT7516/7/8 digital temperature sensor, ADC and DAC"); +MODULE_DESCRIPTION("I2C bus driver for Analog Devices ADT7316/7/9 and ADT7516/7/8 digital temperature sensor, ADC and DAC"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c index 0db8ef5835a0..7f4f0a8245b4 100644 --- a/drivers/staging/iio/addac/adt7316-spi.c +++ b/drivers/staging/iio/addac/adt7316-spi.c @@ -146,6 +146,5 @@ static struct spi_driver adt7316_driver = { module_spi_driver(adt7316_driver); MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); -MODULE_DESCRIPTION("SPI bus driver for Analog Devices ADT7316/7/8 and" - "ADT7516/7/9 digital temperature sensor, ADC and DAC"); +MODULE_DESCRIPTION("SPI bus driver for Analog Devices ADT7316/7/8 and ADT7516/7/9 digital temperature sensor, ADC and DAC"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 1e1356825d6d..80266e801d56 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -412,13 +412,13 @@ static ssize_t adt7316_store_ad_channel(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config2; - unsigned long data = 0; + u8 data; int ret; if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE)) return -EPERM; - ret = strict_strtoul(buf, 10, &data); + ret = kstrtou8(buf, 10, &data); if (ret) return -EINVAL; @@ -823,10 +823,10 @@ static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 dac_config; - unsigned long data = 0; + u8 data; int ret; - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou8(buf, 16, &data); if (ret || data > ADT7316_DA_2VREF_CH_MASK) return -EINVAL; @@ -878,13 +878,13 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 dac_config; - unsigned long data; + u8 data; int ret; if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)) return -EPERM; - ret = strict_strtoul(buf, 10, &data); + ret = kstrtou8(buf, 10, &data); if (ret || data > ADT7316_DA_EN_MODE_MASK) return -EINVAL; @@ -933,7 +933,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 ldac_config; - unsigned long data; + u8 data; int ret; if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) { @@ -941,7 +941,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev, ADT7316_DA_EN_MODE_LDAC) return -EPERM; - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou8(buf, 16, &data); if (ret || data > ADT7316_LDAC_EN_DA_MASK) return -EINVAL; @@ -1079,11 +1079,11 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 ldac_config; - unsigned long data; + u8 data; int ret; if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) { - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou8(buf, 16, &data); if (ret || data > 3) return -EINVAL; @@ -1093,7 +1093,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, else if (data & 0x2) ldac_config |= ADT7516_DAC_CD_IN_VREF; } else { - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou8(buf, 16, &data); if (ret) return -EINVAL; @@ -1281,11 +1281,11 @@ static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip, static ssize_t adt7316_store_temp_offset(struct adt7316_chip_info *chip, int offset_addr, const char *buf, size_t len) { - long data; + int data; u8 val; int ret; - ret = strict_strtol(buf, 10, &data); + ret = kstrtoint(buf, 10, &data); if (ret || data > 127 || data < -128) return -EINVAL; @@ -1442,7 +1442,7 @@ static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, int channel, const char *buf, size_t len) { u8 msb, lsb, offset; - unsigned long data; + u16 data; int ret; if (channel >= ADT7316_DA_MSB_DATA_REGS || @@ -1454,7 +1454,7 @@ static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, offset = chip->dac_bits - 8; - ret = strict_strtoul(buf, 10, &data); + ret = kstrtou16(buf, 10, &data); if (ret || data >= (1 << chip->dac_bits)) return -EINVAL; @@ -1830,11 +1830,11 @@ static ssize_t adt7316_set_int_mask(struct device *dev, { struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - unsigned long data; + u16 data; int ret; u8 mask; - ret = strict_strtoul(buf, 16, &data); + ret = kstrtou16(buf, 16, &data); if (ret || data >= ADT7316_VDD_INT_MASK + 1) return -EINVAL; @@ -1901,7 +1901,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - long data; + int data; u8 val; int ret; @@ -1909,7 +1909,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev, this_attr->address > ADT7316_EX_TEMP_LOW) return -EPERM; - ret = strict_strtol(buf, 10, &data); + ret = kstrtoint(buf, 10, &data); if (ret) return -EINVAL; @@ -2106,11 +2106,9 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, unsigned short *adt7316_platform_data = dev->platform_data; int ret = 0; - indio_dev = iio_device_alloc(sizeof(*chip)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; chip = iio_priv(indio_dev); /* this is only used for device removal purposes */ dev_set_drvdata(dev, indio_dev); @@ -2146,58 +2144,44 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, if (adt7316_platform_data[0]) chip->bus.irq_flags = adt7316_platform_data[0]; - ret = request_threaded_irq(chip->bus.irq, - NULL, - &adt7316_event_handler, - chip->bus.irq_flags | IRQF_ONESHOT, - indio_dev->name, - indio_dev); + ret = devm_request_threaded_irq(dev, chip->bus.irq, + NULL, + &adt7316_event_handler, + chip->bus.irq_flags | + IRQF_ONESHOT, + indio_dev->name, + indio_dev); if (ret) - goto error_free_dev; + return ret; if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH) chip->config1 |= ADT7316_INT_POLARITY; } ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1); - if (ret) { - ret = -EIO; - goto error_unreg_irq; - } + if (ret) + return -EIO; ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, chip->config3); - if (ret) { - ret = -EIO; - goto error_unreg_irq; - } + if (ret) + return -EIO; ret = iio_device_register(indio_dev); if (ret) - goto error_unreg_irq; + return ret; dev_info(dev, "%s temperature sensor, ADC and DAC registered.\n", indio_dev->name); return 0; - -error_unreg_irq: - free_irq(chip->bus.irq, indio_dev); -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; } EXPORT_SYMBOL(adt7316_probe); int adt7316_remove(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct adt7316_chip_info *chip = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (chip->bus.irq) - free_irq(chip->bus.irq, indio_dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index f4a0341cc70c..7e7f9890a642 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -123,14 +123,14 @@ static int ad7150_read_raw(struct iio_dev *indio_dev, } } -static int ad7150_read_event_config(struct iio_dev *indio_dev, u64 event_code) +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) { int ret; u8 threshtype; bool adaptive; struct ad7150_chip_info *chip = iio_priv(indio_dev); - int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING); ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG); if (ret < 0) @@ -139,42 +139,47 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev, u64 event_code) threshtype = (ret >> 5) & 0x03; adaptive = !!(ret & 0x80); - switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) { + switch (type) { case IIO_EV_TYPE_MAG_ADAPTIVE: - if (rising) + if (dir == IIO_EV_DIR_RISING) return adaptive && (threshtype == 0x1); else return adaptive && (threshtype == 0x0); case IIO_EV_TYPE_THRESH_ADAPTIVE: - if (rising) + if (dir == IIO_EV_DIR_RISING) return adaptive && (threshtype == 0x3); else return adaptive && (threshtype == 0x2); case IIO_EV_TYPE_THRESH: - if (rising) + if (dir == IIO_EV_DIR_RISING) return !adaptive && (threshtype == 0x1); else return !adaptive && (threshtype == 0x0); + default: + break; } return -EINVAL; } /* lock should be held */ -static int ad7150_write_event_params(struct iio_dev *indio_dev, u64 event_code) +static int ad7150_write_event_params(struct iio_dev *indio_dev, + unsigned int chan, enum iio_event_type type, + enum iio_event_direction dir) { int ret; u16 value; u8 sens, timeout; struct ad7150_chip_info *chip = iio_priv(indio_dev); - int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code); - int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING); + int rising = (dir == IIO_EV_DIR_RISING); + u64 event_code; + + event_code = IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, chan, type, dir); if (event_code != chip->current_event) return 0; - switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) { + switch (type) { /* Note completely different from the adaptive versions */ case IIO_EV_TYPE_THRESH: value = chip->threshold[rising][chan]; @@ -211,18 +216,20 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, u64 event_code) } static int ad7150_write_event_config(struct iio_dev *indio_dev, - u64 event_code, int state) + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) { u8 thresh_type, cfg, adaptive; int ret; struct ad7150_chip_info *chip = iio_priv(indio_dev); - int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING); + int rising = (dir == IIO_EV_DIR_RISING); + u64 event_code; /* Something must always be turned on */ if (state == 0) return -EINVAL; + event_code = IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, type, dir); if (event_code == chip->current_event) return 0; mutex_lock(&chip->state_lock); @@ -232,7 +239,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev, cfg = ret & ~((0x03 << 5) | (0x1 << 7)); - switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) { + switch (type) { case IIO_EV_TYPE_MAG_ADAPTIVE: adaptive = 1; if (rising) @@ -268,7 +275,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev, chip->current_event = event_code; /* update control attributes */ - ret = ad7150_write_event_params(indio_dev, event_code); + ret = ad7150_write_event_params(indio_dev, chan->channel, type, dir); error_ret: mutex_unlock(&chip->state_lock); @@ -276,53 +283,52 @@ error_ret: } static int ad7150_read_event_value(struct iio_dev *indio_dev, - u64 event_code, - int *val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { - int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code); struct ad7150_chip_info *chip = iio_priv(indio_dev); - int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING); + int rising = (dir == IIO_EV_DIR_RISING); /* Complex register sharing going on here */ - switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) { + switch (type) { case IIO_EV_TYPE_MAG_ADAPTIVE: - *val = chip->mag_sensitivity[rising][chan]; - return 0; - + *val = chip->mag_sensitivity[rising][chan->channel]; + return IIO_VAL_INT; case IIO_EV_TYPE_THRESH_ADAPTIVE: - *val = chip->thresh_sensitivity[rising][chan]; - return 0; - + *val = chip->thresh_sensitivity[rising][chan->channel]; + return IIO_VAL_INT; case IIO_EV_TYPE_THRESH: - *val = chip->threshold[rising][chan]; - return 0; - + *val = chip->threshold[rising][chan->channel]; + return IIO_VAL_INT; default: return -EINVAL; - }; + } } static int ad7150_write_event_value(struct iio_dev *indio_dev, - u64 event_code, - int val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { int ret; struct ad7150_chip_info *chip = iio_priv(indio_dev); - int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code); - int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING); + int rising = (dir == IIO_EV_DIR_RISING); mutex_lock(&chip->state_lock); - switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) { + switch (type) { case IIO_EV_TYPE_MAG_ADAPTIVE: - chip->mag_sensitivity[rising][chan] = val; + chip->mag_sensitivity[rising][chan->channel] = val; break; case IIO_EV_TYPE_THRESH_ADAPTIVE: - chip->thresh_sensitivity[rising][chan] = val; + chip->thresh_sensitivity[rising][chan->channel] = val; break; case IIO_EV_TYPE_THRESH: - chip->threshold[rising][chan] = val; + chip->threshold[rising][chan->channel] = val; break; default: ret = -EINVAL; @@ -330,7 +336,7 @@ static int ad7150_write_event_value(struct iio_dev *indio_dev, } /* write back if active */ - ret = ad7150_write_event_params(indio_dev, event_code); + ret = ad7150_write_event_params(indio_dev, chan->channel, type, dir); error_ret: mutex_unlock(&chip->state_lock); @@ -374,17 +380,22 @@ static ssize_t ad7150_store_timeout(struct device *dev, struct ad7150_chip_info *chip = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address); - int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address) == - IIO_EV_DIR_RISING); + enum iio_event_direction dir; + enum iio_event_type type; + int rising; u8 data; int ret; + type = IIO_EVENT_CODE_EXTRACT_TYPE(this_attr->address); + dir = IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address); + rising = (dir == IIO_EV_DIR_RISING); + ret = kstrtou8(buf, 10, &data); if (ret < 0) return ret; mutex_lock(&chip->state_lock); - switch (IIO_EVENT_CODE_EXTRACT_TYPE(this_attr->address)) { + switch (type) { case IIO_EV_TYPE_MAG_ADAPTIVE: chip->mag_timeout[rising][chan] = data; break; @@ -396,7 +407,7 @@ static ssize_t ad7150_store_timeout(struct device *dev, goto error_ret; } - ret = ad7150_write_event_params(indio_dev, this_attr->address); + ret = ad7150_write_event_params(indio_dev, chan, type, dir); error_ret: mutex_unlock(&chip->state_lock); @@ -424,6 +435,40 @@ static AD7150_TIMEOUT(0, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING); static AD7150_TIMEOUT(1, thresh_adaptive, rising, THRESH_ADAPTIVE, RISING); static AD7150_TIMEOUT(1, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING); +static const struct iio_event_spec ad7150_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH_ADAPTIVE, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH_ADAPTIVE, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_MAG_ADAPTIVE, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_MAG_ADAPTIVE, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + static const struct iio_chan_spec ad7150_channels[] = { { .type = IIO_CAPACITANCE, @@ -431,26 +476,16 @@ static const struct iio_chan_spec ad7150_channels[] = { .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_AVERAGE_RAW), - .event_mask = - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_DIR_FALLING) | - IIO_EV_BIT(IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_DIR_FALLING) + .event_spec = ad7150_events, + .num_event_specs = ARRAY_SIZE(ad7150_events), }, { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 1, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_AVERAGE_RAW), - .event_mask = - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_DIR_FALLING) | - IIO_EV_BIT(IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_DIR_RISING) | - IIO_EV_BIT(IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_DIR_FALLING) + .event_spec = ad7150_events, + .num_event_specs = ARRAY_SIZE(ad7150_events), }, }; @@ -541,10 +576,10 @@ static const struct iio_info ad7150_info = { .event_attrs = &ad7150_event_attribute_group, .driver_module = THIS_MODULE, .read_raw = &ad7150_read_raw, - .read_event_config = &ad7150_read_event_config, - .write_event_config = &ad7150_write_event_config, - .read_event_value = &ad7150_read_event_value, - .write_event_value = &ad7150_write_event_value, + .read_event_config_new = &ad7150_read_event_config, + .write_event_config_new = &ad7150_write_event_config, + .read_event_value_new = &ad7150_read_event_value, + .write_event_value_new = &ad7150_write_event_value, }; /* diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c index 75a533bce021..862d68d99630 100644 --- a/drivers/staging/iio/cdc/ad7746.c +++ b/drivers/staging/iio/cdc/ad7746.c @@ -656,20 +656,21 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_CAPACITANCE: /* 8.192pf / 2^24 */ - *val2 = 488; *val = 0; + *val2 = 488; + ret = IIO_VAL_INT_PLUS_NANO; break; case IIO_VOLTAGE: /* 1170mV / 2^23 */ - *val2 = 139475; - *val = 0; + *val = 1170; + *val2 = 23; + ret = IIO_VAL_FRACTIONAL_LOG2; break; default: - ret = -EINVAL; - goto out; + ret = -EINVAL; + break; } - ret = IIO_VAL_INT_PLUS_NANO; break; default: ret = -EINVAL; diff --git a/drivers/staging/iio/frequency/ad5930.c b/drivers/staging/iio/frequency/ad5930.c index 69e90e9e60ea..a4aeee6ffdf2 100644 --- a/drivers/staging/iio/frequency/ad5930.c +++ b/drivers/staging/iio/frequency/ad5930.c @@ -94,11 +94,9 @@ static int ad5930_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; spi_set_drvdata(spi, idev); st = iio_priv(idev); @@ -110,24 +108,18 @@ static int ad5930_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 16; spi_setup(spi); return 0; - -error_free_dev: - iio_device_free(idev); -error_ret: - return ret; } static int ad5930_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index 4e18380c5141..c7d0307c8e76 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -81,9 +81,9 @@ static ssize_t ad9832_write(struct device *dev, struct ad9832_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + unsigned long val; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoul(buf, 10, &val); if (ret) goto error_ret; @@ -214,14 +214,14 @@ static int ad9832_probe(struct spi_device *spi) return -ENODEV; } - reg = regulator_get(&spi->dev, "vcc"); + reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(reg)) { ret = regulator_enable(reg); if (ret) - goto error_put_reg; + return ret; } - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; @@ -279,47 +279,42 @@ static int ad9832_probe(struct spi_device *spi) ret = spi_sync(st->spi, &st->msg); if (ret) { dev_err(&spi->dev, "device init failed\n"); - goto error_free_device; + goto error_disable_reg; } ret = ad9832_write_frequency(st, AD9832_FREQ0HM, pdata->freq0); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_frequency(st, AD9832_FREQ1HM, pdata->freq1); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_phase(st, AD9832_PHASE0H, pdata->phase0); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_phase(st, AD9832_PHASE1H, pdata->phase1); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_phase(st, AD9832_PHASE2H, pdata->phase2); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9832_write_phase(st, AD9832_PHASE3H, pdata->phase3); if (ret) - goto error_free_device; + goto error_disable_reg; ret = iio_device_register(indio_dev); if (ret) - goto error_free_device; + goto error_disable_reg; return 0; -error_free_device: - iio_device_free(indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); -error_put_reg: - if (!IS_ERR(reg)) - regulator_put(reg); return ret; } @@ -330,11 +325,8 @@ static int ad9832_remove(struct spi_device *spi) struct ad9832_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 5cba3c01f417..86cda6176093 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -70,9 +70,9 @@ static ssize_t ad9834_write(struct device *dev, struct ad9834_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + unsigned long val; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoul(buf, 10, &val); if (ret) goto error_ret; @@ -327,14 +327,14 @@ static int ad9834_probe(struct spi_device *spi) return -ENODEV; } - reg = regulator_get(&spi->dev, "vcc"); + reg = devm_regulator_get(&spi->dev, "vcc"); if (!IS_ERR(reg)) { ret = regulator_enable(reg); if (ret) - goto error_put_reg; + return ret; } - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; @@ -388,39 +388,35 @@ static int ad9834_probe(struct spi_device *spi) ret = spi_sync(st->spi, &st->msg); if (ret) { dev_err(&spi->dev, "device init failed\n"); - goto error_free_device; + goto error_disable_reg; } ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0); if (ret) - goto error_free_device; + goto error_disable_reg; ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1); if (ret) - goto error_free_device; + goto error_disable_reg; ret = iio_device_register(indio_dev); if (ret) - goto error_free_device; + goto error_disable_reg; return 0; -error_free_device: - iio_device_free(indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); -error_put_reg: - if (!IS_ERR(reg)) - regulator_put(reg); + return ret; } @@ -430,11 +426,8 @@ static int ad9834_remove(struct spi_device *spi) struct ad9834_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/frequency/ad9850.c b/drivers/staging/iio/frequency/ad9850.c index 01a8a93031f5..af877ff680e9 100644 --- a/drivers/staging/iio/frequency/ad9850.c +++ b/drivers/staging/iio/frequency/ad9850.c @@ -80,11 +80,9 @@ static int ad9850_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; spi_set_drvdata(spi, idev); st = iio_priv(idev); mutex_init(&st->lock); @@ -96,24 +94,18 @@ static int ad9850_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 16; spi_setup(spi); return 0; - -error_free_dev: - iio_device_free(idev); -error_ret: - return ret; } static int ad9850_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/frequency/ad9852.c b/drivers/staging/iio/frequency/ad9852.c index 1344031232bc..11e4367375d2 100644 --- a/drivers/staging/iio/frequency/ad9852.c +++ b/drivers/staging/iio/frequency/ad9852.c @@ -67,7 +67,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, const char *buf, size_t len) { - struct spi_message msg; struct spi_transfer xfer; int ret; struct ad9852_config *config = (struct ad9852_config *)buf; @@ -78,99 +77,77 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.tx_buf = &config->phajst0[0]; mutex_lock(&st->lock); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 3; xfer.tx_buf = &config->phajst1[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 6; xfer.tx_buf = &config->fretun1[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 6; xfer.tx_buf = &config->fretun2[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 6; xfer.tx_buf = &config->dltafre[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 5; xfer.tx_buf = &config->updtclk[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 4; xfer.tx_buf = &config->ramprat[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 5; xfer.tx_buf = &config->control[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 3; xfer.tx_buf = &config->outpskm[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 2; xfer.tx_buf = &config->outpskr[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 3; xfer.tx_buf = &config->daccntl[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; error_ret: @@ -229,11 +206,9 @@ static int ad9852_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; st = iio_priv(idev); spi_set_drvdata(spi, idev); mutex_init(&st->lock); @@ -245,7 +220,7 @@ static int ad9852_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 8; @@ -253,18 +228,11 @@ static int ad9852_probe(struct spi_device *spi) ad9852_init(st); return 0; - -error_free_dev: - iio_device_free(idev); - -error_ret: - return ret; } static int ad9852_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/frequency/ad9910.c b/drivers/staging/iio/frequency/ad9910.c index e48f874c1fc2..755e0482681a 100644 --- a/drivers/staging/iio/frequency/ad9910.c +++ b/drivers/staging/iio/frequency/ad9910.c @@ -119,7 +119,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, const char *buf, size_t len) { - struct spi_message msg; struct spi_transfer xfer; int ret; struct ad9910_config *config = (struct ad9910_config *)buf; @@ -130,152 +129,118 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.tx_buf = &config->auxdac[0]; mutex_lock(&st->lock); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 5; xfer.tx_buf = &config->ioupd[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 5; xfer.tx_buf = &config->ftw[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 3; xfer.tx_buf = &config->pow[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 5; xfer.tx_buf = &config->asf[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 5; xfer.tx_buf = &config->multc[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->dig_rampl[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->dig_ramps[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 5; xfer.tx_buf = &config->dig_rampr[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep0[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep1[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep2[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep3[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep4[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep5[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep6[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep7[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; error_ret: @@ -288,7 +253,6 @@ static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0); static void ad9910_init(struct ad9910_state *st) { - struct spi_message msg; struct spi_transfer xfer; int ret; u8 cfr[5]; @@ -304,9 +268,7 @@ static void ad9910_init(struct ad9910_state *st) xfer.len = 5; xfer.tx_buf = 𝔠 - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; @@ -319,9 +281,7 @@ static void ad9910_init(struct ad9910_state *st) xfer.len = 5; xfer.tx_buf = 𝔠 - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; @@ -334,9 +294,7 @@ static void ad9910_init(struct ad9910_state *st) xfer.len = 5; xfer.tx_buf = 𝔠 - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; @@ -367,11 +325,9 @@ static int ad9910_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; spi_set_drvdata(spi, idev); st = iio_priv(idev); mutex_init(&st->lock); @@ -383,24 +339,18 @@ static int ad9910_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); ad9910_init(st); return 0; - -error_free_dev: - iio_device_free(idev); -error_ret: - return ret; } static int ad9910_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/frequency/ad9951.c b/drivers/staging/iio/frequency/ad9951.c index 8234e3c915c4..5e8990a0210b 100644 --- a/drivers/staging/iio/frequency/ad9951.c +++ b/drivers/staging/iio/frequency/ad9951.c @@ -60,7 +60,6 @@ static ssize_t ad9951_set_parameter(struct device *dev, const char *buf, size_t len) { - struct spi_message msg; struct spi_transfer xfer; int ret; struct ad9951_config *config = (struct ad9951_config *)buf; @@ -71,36 +70,28 @@ static ssize_t ad9951_set_parameter(struct device *dev, xfer.tx_buf = &config->asf[0]; mutex_lock(&st->lock); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 2; xfer.tx_buf = &config->arr[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 5; xfer.tx_buf = &config->ftw0[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; xfer.len = 3; xfer.tx_buf = &config->ftw1[0]; - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; error_ret: @@ -113,7 +104,6 @@ static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0); static void ad9951_init(struct ad9951_state *st) { - struct spi_message msg; struct spi_transfer xfer; int ret; u8 cfr[5]; @@ -129,9 +119,7 @@ static void ad9951_init(struct ad9951_state *st) xfer.len = 5; xfer.tx_buf = 𝔠 - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; @@ -143,9 +131,7 @@ static void ad9951_init(struct ad9951_state *st) xfer.len = 4; xfer.tx_buf = 𝔠 - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - ret = spi_sync(st->sdev, &msg); + ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret) goto error_ret; @@ -176,11 +162,9 @@ static int ad9951_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_device_alloc(sizeof(*st)); - if (idev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!idev) + return -ENOMEM; spi_set_drvdata(spi, idev); st = iio_priv(idev); mutex_init(&st->lock); @@ -193,25 +177,18 @@ static int ad9951_probe(struct spi_device *spi) ret = iio_device_register(idev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = 2000000; spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); ad9951_init(st); return 0; - -error_free_dev: - iio_device_free(idev); - -error_ret: - return ret; } static int ad9951_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index 0e8e02a3cf5b..1fac9894b18c 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -57,6 +57,20 @@ static const struct iio_dummy_accel_calibscale dummy_scales[] = { { 733, 13, 0x9 }, /* 733.000013 */ }; +#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS + +/* + * simple event - triggered when value rises above + * a threshold + */ +static const struct iio_event_spec iio_dummy_event = { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), +}; + +#endif + /* * iio_dummy_channels - Description of available channels * @@ -90,6 +104,11 @@ static const struct iio_chan_spec iio_dummy_channels[] = { * when converting to standard units (microvolts) */ BIT(IIO_CHAN_INFO_SCALE), + /* + * sampling_frequency + * The frequency in Hz at which the channels are sampled + */ + .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), /* The ordering of elements in the buffer via an enum */ .scan_index = voltage0, .scan_type = { /* Description of storage in buffer */ @@ -99,12 +118,8 @@ static const struct iio_chan_spec iio_dummy_channels[] = { .shift = 0, /* zero shift */ }, #ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS - /* - * simple event - triggered when value rises above - * a threshold - */ - .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), + .event_spec = &iio_dummy_event, + .num_event_specs = 1, #endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */ }, /* Differential ADC channel in_voltage1-voltage2_raw etc*/ @@ -130,6 +145,10 @@ static const struct iio_chan_spec iio_dummy_channels[] = { * input channels of type IIO_VOLTAGE. */ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + /* + * sampling_frequency + * The frequency in Hz at which the channels are sampled + */ .scan_index = diffvoltage1m2, .scan_type = { /* Description of storage in buffer */ .sign = 's', /* signed */ @@ -147,6 +166,7 @@ static const struct iio_chan_spec iio_dummy_channels[] = { .channel2 = 4, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), .scan_index = diffvoltage3m4, .scan_type = { .sign = 's', @@ -173,6 +193,7 @@ static const struct iio_chan_spec iio_dummy_channels[] = { */ BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), .scan_index = accelx, .scan_type = { /* Description of storage in buffer */ .sign = 's', /* signed */ @@ -272,6 +293,11 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, *val2 = st->accel_calibscale->val2; ret = IIO_VAL_INT_PLUS_MICRO; break; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = 3; + *val2 = 33; + ret = IIO_VAL_INT_PLUS_NANO; + break; default: break; } @@ -344,10 +370,10 @@ static const struct iio_info iio_dummy_info = { .read_raw = &iio_dummy_read_raw, .write_raw = &iio_dummy_write_raw, #ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS - .read_event_config = &iio_simple_dummy_read_event_config, - .write_event_config = &iio_simple_dummy_write_event_config, - .read_event_value = &iio_simple_dummy_read_event_value, - .write_event_value = &iio_simple_dummy_write_event_value, + .read_event_config_new = &iio_simple_dummy_read_event_config, + .write_event_config_new = &iio_simple_dummy_write_event_config, + .read_event_value_new = &iio_simple_dummy_read_event_value, + .write_event_value_new = &iio_simple_dummy_write_event_value, #endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */ }; @@ -454,7 +480,8 @@ static int iio_dummy_probe(int index) * buffer, but avoid the output channel being registered by reducing the * number of channels by 1. */ - ret = iio_simple_dummy_configure_buffer(indio_dev, iio_dummy_channels, 5); + ret = iio_simple_dummy_configure_buffer(indio_dev, + iio_dummy_channels, 5); if (ret < 0) goto error_unregister_events; diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h index c9e8702caca4..b126196cdf3d 100644 --- a/drivers/staging/iio/iio_simple_dummy.h +++ b/drivers/staging/iio/iio_simple_dummy.h @@ -45,19 +45,29 @@ struct iio_dummy_state { struct iio_dev; int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev, - u64 event_code); + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir); int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev, - u64 event_code, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state); int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev, - u64 event_code, - int *val); + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, + int *val2); int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev, - u64 event_code, - int val); + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int val, + int val2); int iio_simple_dummy_events_register(struct iio_dev *indio_dev); int iio_simple_dummy_events_unregister(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index 72f400c3cbcb..46c134b2a5d1 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -82,11 +82,8 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) len += 2; } } - /* Store the timestamp at an 8 byte aligned offset */ - if (indio_dev->scan_timestamp) - *(s64 *)((u8 *)data + ALIGN(len, sizeof(s64))) - = iio_get_time_ns(); - iio_push_to_buffers(indio_dev, (u8 *)data); + + iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns()); kfree(data); @@ -102,14 +99,6 @@ done: static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = { /* - * iio_sw_buffer_preenable: - * Generic function for equal sized ring elements + 64 bit timestamp - * Assumes that any combination of channels can be enabled. - * Typically replaced to implement restrictions on what combinations - * can be captured (hardware scan modes). - */ - .preenable = &iio_sw_buffer_preenable, - /* * iio_triggered_buffer_postenable: * Generic function that simply attaches the pollfunc to the trigger. * Replace this to mess with hardware state before we attach the @@ -138,7 +127,7 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, goto error_ret; } - indio_dev->buffer = buffer; + iio_device_attach_buffer(indio_dev, buffer); /* Enable timestamps by default */ buffer->scan_timestamp = true; diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c index 317b77465db4..812ebd05a7fe 100644 --- a/drivers/staging/iio/iio_simple_dummy_events.c +++ b/drivers/staging/iio/iio_simple_dummy_events.c @@ -23,13 +23,17 @@ /** * iio_simple_dummy_read_event_config() - is event enabled? * @indio_dev: the device instance data - * @event_code: event code of the event being queried + * @chan: channel for the event whose state is being queried + * @type: type of the event whose state is being queried + * @dir: direction of the vent whose state is being queried * * This function would normally query the relevant registers or a cache to * discover if the event generation is enabled on the device. */ int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { struct iio_dummy_state *st = iio_priv(indio_dev); @@ -39,7 +43,9 @@ int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev, /** * iio_simple_dummy_write_event_config() - set whether event is enabled * @indio_dev: the device instance data - * @event_code: event code of event being enabled/disabled + * @chan: channel for the event whose state is being set + * @type: type of the event whose state is being set + * @dir: direction of the vent whose state is being set * @state: whether to enable or disable the device. * * This function would normally set the relevant registers on the devices @@ -47,7 +53,9 @@ int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev, * value. */ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev, - u64 event_code, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) { struct iio_dummy_state *st = iio_priv(indio_dev); @@ -56,12 +64,11 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev, * Deliberately over the top code splitting to illustrate * how this is done when multiple events exist. */ - switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + switch (chan->type) { case IIO_VOLTAGE: - switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) { + switch (type) { case IIO_EV_TYPE_THRESH: - if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == - IIO_EV_DIR_RISING) + if (dir == IIO_EV_DIR_RISING) st->event_en = state; else return -EINVAL; @@ -79,7 +86,10 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev, /** * iio_simple_dummy_read_event_value() - get value associated with event * @indio_dev: device instance specific data - * @event_code: event code for the event whose value is being queried + * @chan: channel for the event whose value is being read + * @type: type of the event whose value is being read + * @dir: direction of the vent whose value is being read + * @info: info type of the event whose value is being read * @val: value for the event code. * * Many devices provide a large set of events of which only a subset may @@ -89,25 +99,34 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev, * the enabled event is changed. */ int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev, - u64 event_code, - int *val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { struct iio_dummy_state *st = iio_priv(indio_dev); *val = st->event_val; - return 0; + return IIO_VAL_INT; } /** * iio_simple_dummy_write_event_value() - set value associate with event * @indio_dev: device instance specific data - * @event_code: event code for the event whose value is being set + * @chan: channel for the event whose value is being set + * @type: type of the event whose value is being set + * @dir: direction of the vent whose value is being set + * @info: info type of the event whose value is being set * @val: the value to be set. */ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev, - u64 event_code, - int val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct iio_dummy_state *st = iio_priv(indio_dev); diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 6330af656a0f..0a4298b744e6 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -323,10 +323,10 @@ static ssize_t ad5933_store_frequency(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5933_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long val; + unsigned long val; int ret; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoul(buf, 10, &val); if (ret) return ret; @@ -400,12 +400,12 @@ static ssize_t ad5933_store(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5933_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long val; + u16 val; int i, ret = 0; unsigned short dat; if (this_attr->address != AD5933_IN_PGA_GAIN) { - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; } @@ -434,7 +434,7 @@ static ssize_t ad5933_store(struct device *dev, ret = ad5933_cmd(st, 0); break; case AD5933_OUT_SETTLING_CYCLES: - val = clamp(val, 0L, 0x7FFL); + val = clamp(val, (u16)0, (u16)0x7FF); st->settling_cycles = val; /* 2x, 4x handling, see datasheet */ @@ -448,7 +448,7 @@ static ssize_t ad5933_store(struct device *dev, AD5933_REG_SETTLING_CYCLES, 2, (u8 *)&dat); break; case AD5933_FREQ_POINTS: - val = clamp(val, 0L, 511L); + val = clamp(val, (u16)0, (u16)511); st->freq_points = val; dat = cpu_to_be16(val); @@ -574,10 +574,6 @@ static int ad5933_ring_preenable(struct iio_dev *indio_dev) if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; - ret = iio_sw_buffer_preenable(indio_dev); - if (ret < 0) - return ret; - ret = ad5933_reset(st); if (ret < 0) return ret; @@ -630,10 +626,14 @@ static const struct iio_buffer_setup_ops ad5933_ring_setup_ops = { static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev) { - indio_dev->buffer = iio_kfifo_allocate(indio_dev); - if (!indio_dev->buffer) + struct iio_buffer *buffer; + + buffer = iio_kfifo_allocate(indio_dev); + if (buffer) return -ENOMEM; + iio_device_attach_buffer(indio_dev, buffer); + /* Ring buffer functions - here trigger setup related */ indio_dev->setup_ops = &ad5933_ring_setup_ops; @@ -676,7 +676,7 @@ static void ad5933_work(struct work_struct *work) } else { buf[0] = be16_to_cpu(buf[0]); } - iio_push_to_buffers(indio_dev, (u8 *)buf); + iio_push_to_buffers(indio_dev, buf); } else { /* no data available - try again later */ schedule_delayed_work(&st->work, st->poll_time_jiffies); @@ -703,7 +703,9 @@ static int ad5933_probe(struct i2c_client *client, int ret, voltage_uv = 0; struct ad5933_platform_data *pdata = client->dev.platform_data; struct ad5933_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -716,11 +718,11 @@ static int ad5933_probe(struct i2c_client *client, else st->pdata = pdata; - st->reg = regulator_get(&client->dev, "vcc"); + st->reg = devm_regulator_get(&client->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + return ret; voltage_uv = regulator_get_voltage(st->reg); } @@ -778,11 +780,6 @@ error_unreg_ring: error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); -error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); - - iio_device_free(indio_dev); return ret; } @@ -795,11 +792,8 @@ static int ad5933_remove(struct i2c_client *client) iio_device_unregister(indio_dev); iio_buffer_unregister(indio_dev); iio_kfifo_free(indio_dev->buffer); - if (!IS_ERR(st->reg)) { + if (!IS_ERR(st->reg)) regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index e4998e4d4434..488e690388c9 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -240,7 +240,7 @@ static ssize_t store_range(struct device *dev, unsigned long lval; unsigned int new_range; - if (strict_strtoul(buf, 10, &lval)) + if (kstrtoul(buf, 10, &lval)) return -EINVAL; if (!(lval == 1000UL || lval == 4000UL || @@ -279,18 +279,18 @@ static ssize_t store_resolution(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); int status; - unsigned long lval; + unsigned int val; unsigned int new_adc_bit; - if (strict_strtoul(buf, 10, &lval)) + if (kstrtouint(buf, 10, &val)) return -EINVAL; - if (!(lval == 4 || lval == 8 || lval == 12 || lval == 16)) { + if (!(val == 4 || val == 8 || val == 12 || val == 16)) { dev_err(dev, "The resolution is not supported\n"); return -EINVAL; } mutex_lock(&chip->lock); - status = isl29018_set_resolution(chip, lval, &new_adc_bit); + status = isl29018_set_resolution(chip, val, &new_adc_bit); if (status < 0) { mutex_unlock(&chip->lock); dev_err(dev, "Error in setting resolution\n"); @@ -319,11 +319,11 @@ static ssize_t store_prox_infrared_suppression(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); - unsigned long lval; + int val; - if (strict_strtoul(buf, 10, &lval)) + if (kstrtoint(buf, 10, &val)) return -EINVAL; - if (!(lval == 0UL || lval == 1UL)) { + if (!(val == 0 || val == 1)) { dev_err(dev, "The mode is not supported\n"); return -EINVAL; } @@ -331,7 +331,7 @@ static ssize_t store_prox_infrared_suppression(struct device *dev, /* get the "proximity scheme" i.e. if the chip does on chip infrared suppression (1 means perform on chip suppression) */ mutex_lock(&chip->lock); - chip->prox_scheme = (int)lval; + chip->prox_scheme = val; mutex_unlock(&chip->lock); return count; diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index b377dd3b76ad..f8c659568c38 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -493,9 +493,9 @@ static ssize_t taos_power_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if (value == 0) @@ -536,9 +536,9 @@ static ssize_t taos_gain_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; switch (value) { @@ -582,9 +582,9 @@ static ssize_t taos_als_time_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if ((value < 50) || (value > 650)) @@ -619,9 +619,9 @@ static ssize_t taos_als_trim_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if (value) @@ -644,9 +644,9 @@ static ssize_t taos_als_cal_target_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if (value) @@ -671,9 +671,9 @@ static ssize_t taos_do_calibrate(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - unsigned long value; + int value; - if (strict_strtoul(buf, 0, &value)) + if (kstrtoint(buf, 0, &value)) return -EINVAL; if (value == 1) @@ -815,12 +815,9 @@ static int taos_probe(struct i2c_client *clientp, return -EOPNOTSUPP; } - indio_dev = iio_device_alloc(sizeof(*chip)); - if (indio_dev == NULL) { - ret = -ENOMEM; - dev_err(&clientp->dev, "iio allocation failed\n"); - goto fail1; - } + indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; chip = iio_priv(indio_dev); chip->client = clientp; i2c_set_clientdata(clientp, indio_dev); @@ -835,14 +832,14 @@ static int taos_probe(struct i2c_client *clientp, if (ret < 0) { dev_err(&clientp->dev, "i2c_smbus_write_bytes() to cmd " "reg failed in taos_probe(), err = %d\n", ret); - goto fail2; + return ret; } ret = i2c_smbus_read_byte(clientp); if (ret < 0) { dev_err(&clientp->dev, "i2c_smbus_read_byte from " "reg failed in taos_probe(), err = %d\n", ret); - goto fail2; + return ret; } buf[i] = ret; } @@ -850,14 +847,14 @@ static int taos_probe(struct i2c_client *clientp, if (!taos_tsl258x_device(buf)) { dev_info(&clientp->dev, "i2c device found but does not match " "expected id in taos_probe()\n"); - goto fail2; + return -EINVAL; } ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL)); if (ret < 0) { dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " "failed in taos_probe(), err = %d\n", ret); - goto fail2; + return ret; } indio_dev->info = &tsl2583_info; @@ -867,7 +864,7 @@ static int taos_probe(struct i2c_client *clientp, ret = iio_device_register(indio_dev); if (ret) { dev_err(&clientp->dev, "iio registration failed\n"); - goto fail2; + return ret; } /* Load up the V2 defaults (these are hard coded defaults for now) */ @@ -878,10 +875,6 @@ static int taos_probe(struct i2c_client *clientp, dev_info(&clientp->dev, "Light sensor found.\n"); return 0; -fail1: - iio_device_free(indio_dev); -fail2: - return ret; } #ifdef CONFIG_PM_SLEEP @@ -926,7 +919,6 @@ static SIMPLE_DEV_PM_OPS(taos_pm_ops, taos_suspend, taos_resume); static int taos_remove(struct i2c_client *client) { iio_device_unregister(i2c_get_clientdata(client)); - iio_device_free(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index c99f890cc6c6..18805029d2a9 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -124,11 +124,6 @@ #define TSL2X7X_mA13 0xD0 #define TSL2X7X_MAX_TIMER_CNT (0xFF) -/*Common device IIO EventMask */ -#define TSL2X7X_EVENT_MASK \ - (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \ - IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)), - #define TSL2X7X_MIN_ITIME 3 /* TAOS txx2x7x Device family members */ @@ -550,7 +545,7 @@ prox_poll_err: static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) { /* If Operational settings defined elsewhere.. */ - if (chip->pdata && chip->pdata->platform_default_settings != 0) + if (chip->pdata && chip->pdata->platform_default_settings) memcpy(&(chip->tsl2x7x_settings), chip->pdata->platform_default_settings, sizeof(tsl2x7x_default_settings)); @@ -951,7 +946,6 @@ static ssize_t tsl2x7x_gain_available_show(struct device *dev, case tsl2771: case tmd2771: return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128"); - break; } return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); @@ -1223,12 +1217,14 @@ static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev, } static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); int ret; - if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) + if (chan->type == IIO_INTENSITY) ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10); else ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20); @@ -1237,12 +1233,14 @@ static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev, } static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, - u64 event_code, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int val) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); - if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) { + if (chan->type == IIO_INTENSITY) { if (val) chip->tsl2x7x_settings.interrupts_en |= 0x10; else @@ -1260,13 +1258,16 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, } static int tsl2x7x_write_thresh(struct iio_dev *indio_dev, - u64 event_code, - int val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); - if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) { - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + if (chan->type == IIO_INTENSITY) { + switch (dir) { case IIO_EV_DIR_RISING: chip->tsl2x7x_settings.als_thresh_high = val; break; @@ -1277,7 +1278,7 @@ static int tsl2x7x_write_thresh(struct iio_dev *indio_dev, return -EINVAL; } } else { - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + switch (dir) { case IIO_EV_DIR_RISING: chip->tsl2x7x_settings.prox_thres_high = val; break; @@ -1295,13 +1296,16 @@ static int tsl2x7x_write_thresh(struct iio_dev *indio_dev, } static int tsl2x7x_read_thresh(struct iio_dev *indio_dev, - u64 event_code, - int *val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); - if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) { - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + if (chan->type == IIO_INTENSITY) { + switch (dir) { case IIO_EV_DIR_RISING: *val = chip->tsl2x7x_settings.als_thresh_high; break; @@ -1312,7 +1316,7 @@ static int tsl2x7x_read_thresh(struct iio_dev *indio_dev, return -EINVAL; } } else { - switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + switch (dir) { case IIO_EV_DIR_RISING: *val = chip->tsl2x7x_settings.prox_thres_high; break; @@ -1324,7 +1328,7 @@ static int tsl2x7x_read_thresh(struct iio_dev *indio_dev, } } - return 0; + return IIO_VAL_INT; } static int tsl2x7x_read_raw(struct iio_dev *indio_dev, @@ -1346,7 +1350,6 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev, break; default: return -EINVAL; - break; } break; case IIO_CHAN_INFO_RAW: @@ -1366,7 +1369,6 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev, break; default: return -EINVAL; - break; } break; case IIO_CHAN_INFO_CALIBSCALE: @@ -1419,7 +1421,6 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, case tsl2772: case tmd2772: return -EINVAL; - break; } chip->tsl2x7x_settings.als_gain = 3; break; @@ -1431,7 +1432,6 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, case tsl2771: case tmd2771: return -EINVAL; - break; } chip->tsl2x7x_settings.als_gain = 3; break; @@ -1508,18 +1508,15 @@ static int tsl2x7x_device_id(unsigned char *id, int target) case tsl2671: case tsl2771: return ((*id & 0xf0) == TRITON_ID); - break; case tmd2671: case tmd2771: return ((*id & 0xf0) == HALIBUT_ID); - break; case tsl2572: case tsl2672: case tmd2672: case tsl2772: case tmd2772: return ((*id & 0xf0) == SWORDFISH_ID); - break; } return -EINVAL; @@ -1675,10 +1672,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, + .read_event_value_new = &tsl2x7x_read_thresh, + .write_event_value_new = &tsl2x7x_write_thresh, + .read_event_config_new = &tsl2x7x_read_interrupt_config, + .write_event_config_new = &tsl2x7x_write_interrupt_config, }, [PRX] = { .attrs = &tsl2X7X_device_attr_group_tbl[PRX], @@ -1686,10 +1683,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, + .read_event_value_new = &tsl2x7x_read_thresh, + .write_event_value_new = &tsl2x7x_write_thresh, + .read_event_config_new = &tsl2x7x_read_interrupt_config, + .write_event_config_new = &tsl2x7x_write_interrupt_config, }, [ALSPRX] = { .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX], @@ -1697,10 +1694,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, + .read_event_value_new = &tsl2x7x_read_thresh, + .write_event_value_new = &tsl2x7x_write_thresh, + .read_event_config_new = &tsl2x7x_read_interrupt_config, + .write_event_config_new = &tsl2x7x_write_interrupt_config, }, [PRX2] = { .attrs = &tsl2X7X_device_attr_group_tbl[PRX2], @@ -1708,10 +1705,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, + .read_event_value_new = &tsl2x7x_read_thresh, + .write_event_value_new = &tsl2x7x_write_thresh, + .read_event_config_new = &tsl2x7x_read_interrupt_config, + .write_event_config_new = &tsl2x7x_write_interrupt_config, }, [ALSPRX2] = { .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2], @@ -1719,10 +1716,24 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, + .read_event_value_new = &tsl2x7x_read_thresh, + .write_event_value_new = &tsl2x7x_write_thresh, + .read_event_config_new = &tsl2x7x_read_interrupt_config, + .write_event_config_new = &tsl2x7x_write_interrupt_config, + }, +}; + +static const struct iio_event_spec tsl2x7x_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), }, }; @@ -1741,7 +1752,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS), - .event_mask = TSL2X7X_EVENT_MASK + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, { .type = IIO_INTENSITY, .indexed = 1, @@ -1758,7 +1770,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .event_mask = TSL2X7X_EVENT_MASK + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, }, .chan_table_elements = 1, @@ -1778,7 +1791,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS), - .event_mask = TSL2X7X_EVENT_MASK + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, { .type = IIO_INTENSITY, .indexed = 1, @@ -1789,7 +1803,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .event_mask = TSL2X7X_EVENT_MASK + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, }, .chan_table_elements = 4, @@ -1803,7 +1818,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_mask = TSL2X7X_EVENT_MASK + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, }, .chan_table_elements = 1, @@ -1823,7 +1839,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS), - .event_mask = TSL2X7X_EVENT_MASK + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, { .type = IIO_INTENSITY, .indexed = 1, @@ -1835,7 +1852,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_mask = TSL2X7X_EVENT_MASK + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, }, .chan_table_elements = 4, @@ -1851,7 +1869,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp, struct iio_dev *indio_dev; struct tsl2X7X_chip *chip; - indio_dev = iio_device_alloc(sizeof(*chip)); + indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); if (!indio_dev) return -ENOMEM; @@ -1862,22 +1880,21 @@ static int tsl2x7x_probe(struct i2c_client *clientp, ret = tsl2x7x_i2c_read(chip->client, TSL2X7X_CHIPID, &device_id); if (ret < 0) - goto fail1; + return ret; if ((!tsl2x7x_device_id(&device_id, id->driver_data)) || (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) { dev_info(&chip->client->dev, "%s: i2c device found does not match expected id\n", __func__); - ret = -EINVAL; - goto fail1; + return -EINVAL; } ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); if (ret < 0) { dev_err(&clientp->dev, "%s: write to cmd reg failed. err = %d\n", __func__, ret); - goto fail1; + return ret; } /* ALS and PROX functions can be invoked via user space poll @@ -1899,16 +1916,17 @@ static int tsl2x7x_probe(struct i2c_client *clientp, indio_dev->num_channels = chip->chip_info->chan_table_elements; if (clientp->irq) { - ret = request_threaded_irq(clientp->irq, - NULL, - &tsl2x7x_event_handler, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "TSL2X7X_event", - indio_dev); + ret = devm_request_threaded_irq(&clientp->dev, clientp->irq, + NULL, + &tsl2x7x_event_handler, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + "TSL2X7X_event", + indio_dev); if (ret) { dev_err(&clientp->dev, "%s: irq request failed", __func__); - goto fail1; + return ret; } } @@ -1921,20 +1939,12 @@ static int tsl2x7x_probe(struct i2c_client *clientp, if (ret) { dev_err(&clientp->dev, "%s: iio registration failed\n", __func__); - goto fail2; + return ret; } dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); return 0; - -fail2: - if (clientp->irq) - free_irq(clientp->irq, indio_dev); -fail1: - iio_device_free(indio_dev); - - return ret; } static int tsl2x7x_suspend(struct device *dev) @@ -1980,10 +1990,6 @@ static int tsl2x7x_remove(struct i2c_client *client) tsl2x7x_chip_off(indio_dev); iio_device_unregister(indio_dev); - if (client->irq) - free_irq(client->irq, indio_dev); - - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c index c3f3f539e787..99421f90d189 100644 --- a/drivers/staging/iio/magnetometer/hmc5843.c +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -23,23 +23,17 @@ #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/buffer.h> +#include <linux/iio/triggered_buffer.h> #include <linux/delay.h> #define HMC5843_CONFIG_REG_A 0x00 #define HMC5843_CONFIG_REG_B 0x01 #define HMC5843_MODE_REG 0x02 -#define HMC5843_DATA_OUT_X_MSB_REG 0x03 -#define HMC5843_DATA_OUT_X_LSB_REG 0x04 -#define HMC5843_DATA_OUT_Y_MSB_REG 0x05 -#define HMC5843_DATA_OUT_Y_LSB_REG 0x06 -#define HMC5843_DATA_OUT_Z_MSB_REG 0x07 -#define HMC5843_DATA_OUT_Z_LSB_REG 0x08 -/* Beware: Y and Z are exchanged on HMC5883 */ -#define HMC5883_DATA_OUT_Z_MSB_REG 0x05 -#define HMC5883_DATA_OUT_Z_LSB_REG 0x06 -#define HMC5883_DATA_OUT_Y_MSB_REG 0x07 -#define HMC5883_DATA_OUT_Y_LSB_REG 0x08 +#define HMC5843_DATA_OUT_MSB_REGS 0x03 #define HMC5843_STATUS_REG 0x09 +#define HMC5843_ID_REG 0x0a enum hmc5843_ids { HMC5843_ID, @@ -54,19 +48,13 @@ enum hmc5843_ids { */ #define HMC5843_RANGE_GAIN_OFFSET 0x05 #define HMC5843_RANGE_GAIN_DEFAULT 0x01 -#define HMC5843_RANGE_GAIN_MAX 0x07 +#define HMC5843_RANGE_GAINS 8 -/* - * Device status - */ +/* Device status */ #define HMC5843_DATA_READY 0x01 #define HMC5843_DATA_OUTPUT_LOCK 0x02 -/* Does not exist on HMC5883, not used */ -#define HMC5843_VOLTAGE_REGULATOR_ENABLED 0x04 -/* - * Mode register configuration - */ +/* Mode register configuration */ #define HMC5843_MODE_CONVERSION_CONTINUOUS 0x00 #define HMC5843_MODE_CONVERSION_SINGLE 0x01 #define HMC5843_MODE_IDLE 0x02 @@ -78,80 +66,29 @@ enum hmc5843_ids { * HMC5883: Typical data output rate */ #define HMC5843_RATE_OFFSET 0x02 -#define HMC5843_RATE_BITMASK 0x1C -#define HMC5843_RATE_NOT_USED 0x07 +#define HMC5843_RATE_DEFAULT 0x04 +#define HMC5843_RATES 7 -/* - * Device measurement configuration - */ +/* Device measurement configuration */ #define HMC5843_MEAS_CONF_NORMAL 0x00 #define HMC5843_MEAS_CONF_POSITIVE_BIAS 0x01 #define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02 -#define HMC5843_MEAS_CONF_NOT_USED 0x03 #define HMC5843_MEAS_CONF_MASK 0x03 -/* - * Scaling factors: 10000000/Gain - */ -static const int hmc5843_regval_to_nanoscale[] = { +/* Scaling factors: 10000000/Gain */ +static const int hmc5843_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { 6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714 }; -static const int hmc5883_regval_to_nanoscale[] = { +static const int hmc5883_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662 }; -static const int hmc5883l_regval_to_nanoscale[] = { +static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { 7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478 }; /* - * From the HMC5843 datasheet: - * Value | Sensor input field range (Ga) | Gain (counts/milli-Gauss) - * 0 | (+-)0.7 | 1620 - * 1 | (+-)1.0 | 1300 - * 2 | (+-)1.5 | 970 - * 3 | (+-)2.0 | 780 - * 4 | (+-)3.2 | 530 - * 5 | (+-)3.8 | 460 - * 6 | (+-)4.5 | 390 - * 7 | (+-)6.5 | 280 - * - * From the HMC5883 datasheet: - * Value | Recommended sensor field range (Ga) | Gain (counts/Gauss) - * 0 | (+-)0.9 | 1280 - * 1 | (+-)1.2 | 1024 - * 2 | (+-)1.9 | 768 - * 3 | (+-)2.5 | 614 - * 4 | (+-)4.0 | 415 - * 5 | (+-)4.6 | 361 - * 6 | (+-)5.5 | 307 - * 7 | (+-)7.9 | 219 - * - * From the HMC5883L datasheet: - * Value | Recommended sensor field range (Ga) | Gain (LSB/Gauss) - * 0 | (+-)0.88 | 1370 - * 1 | (+-)1.3 | 1090 - * 2 | (+-)1.9 | 820 - * 3 | (+-)2.5 | 660 - * 4 | (+-)4.0 | 440 - * 5 | (+-)4.7 | 390 - * 6 | (+-)5.6 | 330 - * 7 | (+-)8.1 | 230 - */ -static const int hmc5843_regval_to_input_field_mga[] = { - 700, 1000, 1500, 2000, 3200, 3800, 4500, 6500 -}; - -static const int hmc5883_regval_to_input_field_mga[] = { - 900, 1200, 1900, 2500, 4000, 4600, 5500, 7900 -}; - -static const int hmc5883l_regval_to_input_field_mga[] = { - 880, 1300, 1900, 2500, 4000, 4700, 5600, 8100 -}; - -/* * From the datasheet: * Value | HMC5843 | HMC5883/HMC5883L * | Data output rate (Hz) | Data output rate (Hz) @@ -164,141 +101,94 @@ static const int hmc5883l_regval_to_input_field_mga[] = { * 6 | 50 | 75 * 7 | Not used | Not used */ -static const char * const hmc5843_regval_to_sample_freq[] = { - "0.5", "1", "2", "5", "10", "20", "50", +static const int hmc5843_regval_to_samp_freq[7][2] = { + {0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0} }; -static const char * const hmc5883_regval_to_sample_freq[] = { - "0.75", "1.5", "3", "7.5", "15", "30", "75", +static const int hmc5883_regval_to_samp_freq[7][2] = { + {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, + {75, 0} }; /* Describe chip variants */ struct hmc5843_chip_info { const struct iio_chan_spec *channels; - const char * const *regval_to_sample_freq; - const int *regval_to_input_field_mga; + const int (*regval_to_samp_freq)[2]; const int *regval_to_nanoscale; }; /* Each client has this additional data */ struct hmc5843_data { + struct i2c_client *client; struct mutex lock; u8 rate; u8 meas_conf; u8 operating_mode; u8 range; const struct hmc5843_chip_info *variant; + __be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */ }; /* The lower two bits contain the current conversion mode */ -static s32 hmc5843_configure(struct i2c_client *client, - u8 operating_mode) +static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode) { - return i2c_smbus_write_byte_data(client, - HMC5843_MODE_REG, + int ret; + + mutex_lock(&data->lock); + ret = i2c_smbus_write_byte_data(data->client, HMC5843_MODE_REG, operating_mode & HMC5843_MODE_MASK); + if (ret >= 0) + data->operating_mode = operating_mode; + mutex_unlock(&data->lock); + + return ret; } -/* Return the measurement value from the specified channel */ -static int hmc5843_read_measurement(struct iio_dev *indio_dev, - int address, - int *val) +static int hmc5843_wait_measurement(struct hmc5843_data *data) { - struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); - struct hmc5843_data *data = iio_priv(indio_dev); s32 result; int tries = 150; - mutex_lock(&data->lock); while (tries-- > 0) { - result = i2c_smbus_read_byte_data(client, + result = i2c_smbus_read_byte_data(data->client, HMC5843_STATUS_REG); + if (result < 0) + return result; if (result & HMC5843_DATA_READY) break; msleep(20); } if (tries < 0) { - dev_err(&client->dev, "data not ready\n"); - mutex_unlock(&data->lock); + dev_err(&data->client->dev, "data not ready\n"); return -EIO; } - result = i2c_smbus_read_word_swapped(client, address); - mutex_unlock(&data->lock); - if (result < 0) - return -EINVAL; - - *val = sign_extend32(result, 15); - return IIO_VAL_INT; -} - -/* - * From the datasheet: - * 0 - Continuous-Conversion Mode: In continuous-conversion mode, the - * device continuously performs conversions and places the result in - * the data register. - * - * 1 - Single-Conversion Mode : Device performs a single measurement, - * sets RDY high and returns to sleep mode. - * - * 2 - Idle Mode : Device is placed in idle mode. - * - * 3 - Sleep Mode : Device is placed in sleep mode. - * - */ -static ssize_t hmc5843_show_operating_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct hmc5843_data *data = iio_priv(indio_dev); - return sprintf(buf, "%d\n", data->operating_mode); + return 0; } -static ssize_t hmc5843_set_operating_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +/* Return the measurement value from the specified channel */ +static int hmc5843_read_measurement(struct hmc5843_data *data, + int idx, int *val) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); - struct hmc5843_data *data = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - unsigned long operating_mode = 0; - s32 status; - int error; + s32 result; + __be16 values[3]; mutex_lock(&data->lock); - error = kstrtoul(buf, 10, &operating_mode); - if (error) { - count = error; - goto exit; - } - dev_dbg(dev, "set conversion mode to %lu\n", operating_mode); - if (operating_mode > HMC5843_MODE_SLEEP) { - count = -EINVAL; - goto exit; - } - - status = i2c_smbus_write_byte_data(client, this_attr->address, - operating_mode); - if (status) { - count = -EINVAL; - goto exit; + result = hmc5843_wait_measurement(data); + if (result < 0) { + mutex_unlock(&data->lock); + return result; } - data->operating_mode = operating_mode; - -exit: + result = i2c_smbus_read_i2c_block_data(data->client, + HMC5843_DATA_OUT_MSB_REGS, sizeof(values), (u8 *) values); mutex_unlock(&data->lock); - return count; -} + if (result < 0) + return -EINVAL; -static IIO_DEVICE_ATTR(operating_mode, - S_IWUSR | S_IRUGO, - hmc5843_show_operating_mode, - hmc5843_set_operating_mode, - HMC5843_MODE_REG); + *val = sign_extend32(be16_to_cpu(values[idx]), 15); + return IIO_VAL_INT; +} /* * API for setting the measurement configuration to @@ -318,23 +208,26 @@ static IIO_DEVICE_ATTR(operating_mode, * and BN. * */ -static s32 hmc5843_set_meas_conf(struct i2c_client *client, - u8 meas_conf) +static s32 hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf) { - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct hmc5843_data *data = iio_priv(indio_dev); - u8 reg_val; - reg_val = (meas_conf & HMC5843_MEAS_CONF_MASK) | - (data->rate << HMC5843_RATE_OFFSET); - return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val); + int ret; + + mutex_lock(&data->lock); + ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A, + (meas_conf & HMC5843_MEAS_CONF_MASK) | + (data->rate << HMC5843_RATE_OFFSET)); + if (ret >= 0) + data->meas_conf = meas_conf; + mutex_unlock(&data->lock); + + return ret; } static ssize_t hmc5843_show_measurement_configuration(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct hmc5843_data *data = iio_priv(indio_dev); + struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); return sprintf(buf, "%d\n", data->meas_conf); } @@ -343,29 +236,19 @@ static ssize_t hmc5843_set_measurement_configuration(struct device *dev, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); - struct hmc5843_data *data = iio_priv(indio_dev); + struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); unsigned long meas_conf = 0; - int error; + int ret; - error = kstrtoul(buf, 10, &meas_conf); - if (error) - return error; - if (meas_conf >= HMC5843_MEAS_CONF_NOT_USED) + ret = kstrtoul(buf, 10, &meas_conf); + if (ret) + return ret; + if (meas_conf >= HMC5843_MEAS_CONF_MASK) return -EINVAL; - mutex_lock(&data->lock); - dev_dbg(dev, "set measurement configuration to %lu\n", meas_conf); - if (hmc5843_set_meas_conf(client, meas_conf)) { - count = -EINVAL; - goto exit; - } - data->meas_conf = meas_conf; + ret = hmc5843_set_meas_conf(data, meas_conf); -exit: - mutex_unlock(&data->lock); - return count; + return (ret < 0) ? ret : count; } static IIO_DEVICE_ATTR(meas_conf, @@ -374,211 +257,221 @@ static IIO_DEVICE_ATTR(meas_conf, hmc5843_set_measurement_configuration, 0); -static ssize_t hmc5843_show_sampling_frequencies_available(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t hmc5843_show_samp_freq_avail(struct device *dev, + struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct hmc5843_data *data = iio_priv(indio_dev); - ssize_t total_n = 0; + struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); + size_t len = 0; int i; - for (i = 0; i < HMC5843_RATE_NOT_USED; i++) { - ssize_t n = sprintf(buf, "%s ", data->variant->regval_to_sample_freq[i]); - buf += n; - total_n += n; - } + for (i = 0; i < HMC5843_RATES; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, + "%d.%d ", data->variant->regval_to_samp_freq[i][0], + data->variant->regval_to_samp_freq[i][1]); + /* replace trailing space by newline */ - buf[-1] = '\n'; + buf[len - 1] = '\n'; - return total_n; + return len; } -static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_sampling_frequencies_available); +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_samp_freq_avail); -static s32 hmc5843_set_rate(struct i2c_client *client, - u8 rate) +static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate) { - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct hmc5843_data *data = iio_priv(indio_dev); - u8 reg_val; + int ret; - if (rate >= HMC5843_RATE_NOT_USED) { - dev_err(&client->dev, - "data output rate is not supported\n"); - return -EINVAL; - } + mutex_lock(&data->lock); + ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A, + data->meas_conf | (rate << HMC5843_RATE_OFFSET)); + if (ret >= 0) + data->rate = rate; + mutex_unlock(&data->lock); - reg_val = data->meas_conf | (rate << HMC5843_RATE_OFFSET); - return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val); + return ret; } -static int hmc5843_check_sampling_frequency(struct hmc5843_data *data, - const char *buf) +static int hmc5843_get_samp_freq_index(struct hmc5843_data *data, + int val, int val2) { - const char * const *samp_freq = data->variant->regval_to_sample_freq; int i; - for (i = 0; i < HMC5843_RATE_NOT_USED; i++) { - if (sysfs_streq(buf, samp_freq[i])) + for (i = 0; i < HMC5843_RATES; i++) + if (val == data->variant->regval_to_samp_freq[i][0] && + val2 == data->variant->regval_to_samp_freq[i][1]) return i; - } return -EINVAL; } -static ssize_t hmc5843_set_sampling_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range) { - - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); - struct hmc5843_data *data = iio_priv(indio_dev); - int rate; - - rate = hmc5843_check_sampling_frequency(data, buf); - if (rate < 0) { - dev_err(&client->dev, - "sampling frequency is not supported\n"); - return rate; - } + int ret; mutex_lock(&data->lock); - dev_dbg(dev, "set rate to %d\n", rate); - if (hmc5843_set_rate(client, rate)) { - count = -EINVAL; - goto exit; - } - data->rate = rate; - -exit: + ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_B, + range << HMC5843_RANGE_GAIN_OFFSET); + if (ret >= 0) + data->range = range; mutex_unlock(&data->lock); - return count; + + return ret; } -static ssize_t hmc5843_show_sampling_frequency(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hmc5843_show_scale_avail(struct device *dev, + struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct hmc5843_data *data = iio_priv(indio_dev); - s32 rate; + struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); - rate = i2c_smbus_read_byte_data(client, this_attr->address); - if (rate < 0) - return rate; - rate = (rate & HMC5843_RATE_BITMASK) >> HMC5843_RATE_OFFSET; - return sprintf(buf, "%s\n", data->variant->regval_to_sample_freq[rate]); -} + size_t len = 0; + int i; -static IIO_DEVICE_ATTR(sampling_frequency, - S_IWUSR | S_IRUGO, - hmc5843_show_sampling_frequency, - hmc5843_set_sampling_frequency, - HMC5843_CONFIG_REG_A); + for (i = 0; i < HMC5843_RANGE_GAINS; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, + "0.%09d ", data->variant->regval_to_nanoscale[i]); -static ssize_t hmc5843_show_range_gain(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - u8 range; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct hmc5843_data *data = iio_priv(indio_dev); + /* replace trailing space by newline */ + buf[len - 1] = '\n'; - range = data->range; - return sprintf(buf, "%d\n", data->variant->regval_to_input_field_mga[range]); + return len; } -static ssize_t hmc5843_set_range_gain(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct hmc5843_data *data = iio_priv(indio_dev); - unsigned long range = 0; - int error; +static IIO_DEVICE_ATTR(scale_available, S_IRUGO, + hmc5843_show_scale_avail, NULL, 0); - mutex_lock(&data->lock); - error = kstrtoul(buf, 10, &range); - if (error) { - count = error; - goto exit; - } - dev_dbg(dev, "set range to %lu\n", range); +static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2) +{ + int i; - if (range > HMC5843_RANGE_GAIN_MAX) { - count = -EINVAL; - goto exit; - } + if (val != 0) + return -EINVAL; - data->range = range; - range = range << HMC5843_RANGE_GAIN_OFFSET; - if (i2c_smbus_write_byte_data(client, this_attr->address, range)) - count = -EINVAL; + for (i = 0; i < HMC5843_RANGE_GAINS; i++) + if (val2 == data->variant->regval_to_nanoscale[i]) + return i; -exit: - mutex_unlock(&data->lock); - return count; + return -EINVAL; } -static IIO_DEVICE_ATTR(in_magn_range, - S_IWUSR | S_IRUGO, - hmc5843_show_range_gain, - hmc5843_set_range_gain, - HMC5843_CONFIG_REG_B); - static int hmc5843_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + int *val, int *val2, long mask) { struct hmc5843_data *data = iio_priv(indio_dev); switch (mask) { case IIO_CHAN_INFO_RAW: - return hmc5843_read_measurement(indio_dev, - chan->address, - val); + return hmc5843_read_measurement(data, chan->scan_index, val); case IIO_CHAN_INFO_SCALE: *val = 0; *val2 = data->variant->regval_to_nanoscale[data->range]; return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = data->variant->regval_to_samp_freq[data->rate][0]; + *val2 = data->variant->regval_to_samp_freq[data->rate][1]; + return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; } -#define HMC5843_CHANNEL(axis, addr) \ +static int hmc5843_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct hmc5843_data *data = iio_priv(indio_dev); + int rate, range; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + rate = hmc5843_get_samp_freq_index(data, val, val2); + if (rate < 0) + return -EINVAL; + + return hmc5843_set_samp_freq(data, rate); + case IIO_CHAN_INFO_SCALE: + range = hmc5843_get_scale_index(data, val, val2); + if (range < 0) + return -EINVAL; + + return hmc5843_set_range_gain(data, range); + default: + return -EINVAL; + } +} + +static int hmc5843_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static irqreturn_t hmc5843_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct hmc5843_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->lock); + ret = hmc5843_wait_measurement(data); + if (ret < 0) { + mutex_unlock(&data->lock); + goto done; + } + + ret = i2c_smbus_read_i2c_block_data(data->client, + HMC5843_DATA_OUT_MSB_REGS, 3 * sizeof(__be16), + (u8 *) data->buffer); + mutex_unlock(&data->lock); + if (ret < 0) + goto done; + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_get_time_ns()); + +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +#define HMC5843_CHANNEL(axis, idx) \ { \ .type = IIO_MAGN, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .address = addr \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = idx, \ + .scan_type = IIO_ST('s', 16, 16, IIO_BE), \ } static const struct iio_chan_spec hmc5843_channels[] = { - HMC5843_CHANNEL(X, HMC5843_DATA_OUT_X_MSB_REG), - HMC5843_CHANNEL(Y, HMC5843_DATA_OUT_Y_MSB_REG), - HMC5843_CHANNEL(Z, HMC5843_DATA_OUT_Z_MSB_REG), + HMC5843_CHANNEL(X, 0), + HMC5843_CHANNEL(Y, 1), + HMC5843_CHANNEL(Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), }; +/* Beware: Y and Z are exchanged on HMC5883 */ static const struct iio_chan_spec hmc5883_channels[] = { - HMC5843_CHANNEL(X, HMC5843_DATA_OUT_X_MSB_REG), - HMC5843_CHANNEL(Y, HMC5883_DATA_OUT_Y_MSB_REG), - HMC5843_CHANNEL(Z, HMC5883_DATA_OUT_Z_MSB_REG), + HMC5843_CHANNEL(X, 0), + HMC5843_CHANNEL(Z, 1), + HMC5843_CHANNEL(Y, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), }; static struct attribute *hmc5843_attributes[] = { &iio_dev_attr_meas_conf.dev_attr.attr, - &iio_dev_attr_operating_mode.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_dev_attr_in_magn_range.dev_attr.attr, + &iio_dev_attr_scale_available.dev_attr.attr, &iio_dev_attr_sampling_frequency_available.dev_attr.attr, NULL }; @@ -590,89 +483,101 @@ static const struct attribute_group hmc5843_group = { static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = { [HMC5843_ID] = { .channels = hmc5843_channels, - .regval_to_sample_freq = hmc5843_regval_to_sample_freq, - .regval_to_input_field_mga = - hmc5843_regval_to_input_field_mga, + .regval_to_samp_freq = hmc5843_regval_to_samp_freq, .regval_to_nanoscale = hmc5843_regval_to_nanoscale, }, [HMC5883_ID] = { .channels = hmc5883_channels, - .regval_to_sample_freq = hmc5883_regval_to_sample_freq, - .regval_to_input_field_mga = - hmc5883_regval_to_input_field_mga, + .regval_to_samp_freq = hmc5883_regval_to_samp_freq, .regval_to_nanoscale = hmc5883_regval_to_nanoscale, }, [HMC5883L_ID] = { .channels = hmc5883_channels, - .regval_to_sample_freq = hmc5883_regval_to_sample_freq, - .regval_to_input_field_mga = - hmc5883l_regval_to_input_field_mga, + .regval_to_samp_freq = hmc5883_regval_to_samp_freq, .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, }, }; -/* Called when we have found a new HMC58X3 */ -static void hmc5843_init_client(struct i2c_client *client, - const struct i2c_device_id *id) +static int hmc5843_init(struct hmc5843_data *data) { - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct hmc5843_data *data = iio_priv(indio_dev); - - data->variant = &hmc5843_chip_info_tbl[id->driver_data]; - indio_dev->channels = data->variant->channels; - indio_dev->num_channels = 3; - hmc5843_set_meas_conf(client, data->meas_conf); - hmc5843_set_rate(client, data->rate); - hmc5843_configure(client, data->operating_mode); - i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_B, data->range); - mutex_init(&data->lock); + int ret; + u8 id[3]; + + ret = i2c_smbus_read_i2c_block_data(data->client, HMC5843_ID_REG, + sizeof(id), id); + if (ret < 0) + return ret; + if (id[0] != 'H' || id[1] != '4' || id[2] != '3') { + dev_err(&data->client->dev, "no HMC5843/5883/5883L sensor\n"); + return -ENODEV; + } - pr_info("%s initialized\n", id->name); + ret = hmc5843_set_meas_conf(data, HMC5843_MEAS_CONF_NORMAL); + if (ret < 0) + return ret; + ret = hmc5843_set_samp_freq(data, HMC5843_RATE_DEFAULT); + if (ret < 0) + return ret; + ret = hmc5843_set_range_gain(data, HMC5843_RANGE_GAIN_DEFAULT); + if (ret < 0) + return ret; + return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS); } static const struct iio_info hmc5843_info = { .attrs = &hmc5843_group, .read_raw = &hmc5843_read_raw, + .write_raw = &hmc5843_write_raw, + .write_raw_get_fmt = &hmc5843_write_raw_get_fmt, .driver_module = THIS_MODULE, }; +static const unsigned long hmc5843_scan_masks[] = {0x7, 0}; + static int hmc5843_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct hmc5843_data *data; struct iio_dev *indio_dev; - int err = 0; + int ret; - indio_dev = iio_device_alloc(sizeof(*data)); - if (indio_dev == NULL) { - err = -ENOMEM; - goto exit; - } + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; /* default settings at probe */ data = iio_priv(indio_dev); - data->meas_conf = HMC5843_MEAS_CONF_NORMAL; - data->range = HMC5843_RANGE_GAIN_DEFAULT; - data->operating_mode = HMC5843_MODE_CONVERSION_CONTINUOUS; + data->client = client; + data->variant = &hmc5843_chip_info_tbl[id->driver_data]; + mutex_init(&data->lock); i2c_set_clientdata(client, indio_dev); - hmc5843_init_client(client, id); - indio_dev->info = &hmc5843_info; indio_dev->name = id->name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = data->variant->channels; + indio_dev->num_channels = 4; + indio_dev->available_scan_masks = hmc5843_scan_masks; + + ret = hmc5843_init(data); + if (ret < 0) + return ret; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + hmc5843_trigger_handler, NULL); + if (ret < 0) + return ret; - err = iio_device_register(indio_dev); - if (err) - goto exit_free2; + ret = iio_device_register(indio_dev); + if (ret < 0) + goto buffer_cleanup; return 0; -exit_free2: - iio_device_free(indio_dev); -exit: - return err; +buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + return ret; } static int hmc5843_remove(struct i2c_client *client) @@ -680,9 +585,10 @@ static int hmc5843_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); iio_device_unregister(indio_dev); - /* sleep mode to save power */ - hmc5843_configure(client, HMC5843_MODE_SLEEP); - iio_device_free(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + + /* sleep mode to save power */ + hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP); return 0; } @@ -690,19 +596,18 @@ static int hmc5843_remove(struct i2c_client *client) #ifdef CONFIG_PM_SLEEP static int hmc5843_suspend(struct device *dev) { - hmc5843_configure(to_i2c_client(dev), HMC5843_MODE_SLEEP); - return 0; + struct hmc5843_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + + return hmc5843_set_mode(data, HMC5843_MODE_SLEEP); } static int hmc5843_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct hmc5843_data *data = iio_priv(indio_dev); + struct hmc5843_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); - hmc5843_configure(client, data->operating_mode); - - return 0; + return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS); } static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume); @@ -730,6 +635,6 @@ static struct i2c_driver hmc5843_driver = { }; module_i2c_driver(hmc5843_driver); -MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com"); +MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com>"); MODULE_DESCRIPTION("HMC5843/5883/5883L driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 74025fbae679..6200335d12f7 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -186,9 +186,9 @@ static ssize_t ade7753_write_8bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = ade7753_spi_write_reg_8(dev, this_attr->address, val); @@ -204,9 +204,9 @@ static ssize_t ade7753_write_16bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = ade7753_spi_write_reg_16(dev, this_attr->address, val); @@ -399,11 +399,11 @@ static ssize_t ade7753_write_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); - unsigned long val; + u16 val; int ret; u16 reg, t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; if (val == 0) @@ -497,11 +497,9 @@ static int ade7753_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -517,19 +515,13 @@ static int ade7753_probe(struct spi_device *spi) /* Get the device into a sane initial state */ ret = ade7753_initial_setup(indio_dev); if (ret) - goto error_free_dev; + return ret; ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; return 0; - -error_free_dev: - iio_device_free(indio_dev); - -error_ret: - return ret; } /* fixme, confirm ordering in this function */ @@ -539,7 +531,6 @@ static int ade7753_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ade7753_stop_device(&indio_dev->dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index f649ebe55a04..2e046f6e4fb4 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -186,9 +186,9 @@ static ssize_t ade7754_write_8bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = ade7754_spi_write_reg_8(dev, this_attr->address, val); @@ -204,9 +204,9 @@ static ssize_t ade7754_write_16bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = ade7754_spi_write_reg_16(dev, this_attr->address, val); @@ -419,11 +419,11 @@ static ssize_t ade7754_write_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); - unsigned long val; + u16 val; int ret; u8 reg, t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; if (val == 0) @@ -520,11 +520,9 @@ static int ade7754_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -540,18 +538,12 @@ static int ade7754_probe(struct spi_device *spi) /* Get the device into a sane initial state */ ret = ade7754_initial_setup(indio_dev); if (ret) - goto error_free_dev; + return ret; ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; return 0; - -error_free_dev: - iio_device_free(indio_dev); - -error_ret: - return ret; } /* fixme, confirm ordering in this function */ @@ -561,7 +553,6 @@ static int ade7754_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ade7754_stop_device(&indio_dev->dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 6005d4aab0c3..cba183e24838 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -269,9 +269,9 @@ static ssize_t ade7758_write_8bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = ade7758_spi_write_reg_8(dev, this_attr->address, val); @@ -287,9 +287,9 @@ static ssize_t ade7758_write_16bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = ade7758_spi_write_reg_16(dev, this_attr->address, val); @@ -502,11 +502,11 @@ static ssize_t ade7758_write_frequency(struct device *dev, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - unsigned long val; + u16 val; int ret; u8 reg, t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; @@ -849,12 +849,11 @@ static int ade7758_probe(struct spi_device *spi) { int ret; struct ade7758_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + struct iio_dev *indio_dev; - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + 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 */ @@ -862,10 +861,8 @@ static int ade7758_probe(struct spi_device *spi) /* Allocate the comms buffers */ st->rx = kcalloc(ADE7758_MAX_RX, sizeof(*st->rx), GFP_KERNEL); - if (st->rx == NULL) { - ret = -ENOMEM; - goto error_free_dev; - } + if (!st->rx) + return -ENOMEM; st->tx = kcalloc(ADE7758_MAX_TX, sizeof(*st->tx), GFP_KERNEL); if (st->tx == NULL) { ret = -ENOMEM; @@ -920,9 +917,6 @@ error_free_tx: kfree(st->tx); error_free_rx: kfree(st->rx); -error_free_dev: - iio_device_free(indio_dev); -error_ret: return ret; } @@ -939,8 +933,6 @@ static int ade7758_remove(struct spi_device *spi) kfree(st->tx); kfree(st->rx); - iio_device_free(indio_dev); - return 0; } diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index 7d5db7175578..c0accf8cce93 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -69,11 +69,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p) if (ade7758_spi_read_burst(indio_dev) >= 0) *dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF; - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - dat64[1] = pf->timestamp; - - iio_push_to_buffers(indio_dev, (u8 *)dat64); + iio_push_to_buffers_with_timestamp(indio_dev, dat64, pf->timestamp); iio_trigger_notify_done(indio_dev->trig); @@ -91,15 +87,10 @@ static int ade7758_ring_preenable(struct iio_dev *indio_dev) { struct ade7758_state *st = iio_priv(indio_dev); unsigned channel; - int ret; if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; - ret = iio_sw_buffer_preenable(indio_dev); - if (ret < 0) - return ret; - channel = find_first_bit(indio_dev->active_scan_mask, indio_dev->masklength); @@ -125,14 +116,17 @@ void ade7758_unconfigure_ring(struct iio_dev *indio_dev) int ade7758_configure_ring(struct iio_dev *indio_dev) { struct ade7758_state *st = iio_priv(indio_dev); + struct iio_buffer *buffer; int ret = 0; - indio_dev->buffer = iio_kfifo_allocate(indio_dev); - if (!indio_dev->buffer) { + buffer = iio_kfifo_allocate(indio_dev); + if (!buffer) { ret = -ENOMEM; return ret; } + iio_device_attach_buffer(indio_dev, buffer); + indio_dev->setup_ops = &ade7758_ring_setup_ops; indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index d214ac4932cb..145f896aae2b 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -185,9 +185,9 @@ static ssize_t ade7759_write_8bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = ade7759_spi_write_reg_8(dev, this_attr->address, val); @@ -203,9 +203,9 @@ static ssize_t ade7759_write_16bit(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = ade7759_spi_write_reg_16(dev, this_attr->address, val); @@ -360,11 +360,11 @@ static ssize_t ade7759_write_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); - unsigned long val; + u16 val; int ret; u16 reg, t; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) return ret; if (val == 0) @@ -444,11 +444,9 @@ static int ade7759_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -463,18 +461,13 @@ static int ade7759_probe(struct spi_device *spi) /* Get the device into a sane initial state */ ret = ade7759_initial_setup(indio_dev); if (ret) - goto error_free_dev; + return ret; ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; } /* fixme, confirm ordering in this function */ @@ -484,7 +477,6 @@ static int ade7759_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ade7759_stop_device(&indio_dev->dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c index db9ef6c86c1e..5b33c7f1aa91 100644 --- a/drivers/staging/iio/meter/ade7854-i2c.c +++ b/drivers/staging/iio/meter/ade7854-i2c.c @@ -208,7 +208,7 @@ static int ade7854_i2c_probe(struct i2c_client *client, struct ade7854_state *st; struct iio_dev *indio_dev; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); @@ -225,8 +225,6 @@ static int ade7854_i2c_probe(struct i2c_client *client, st->irq = client->irq; ret = ade7854_probe(indio_dev, &client->dev); - if (ret) - iio_device_free(indio_dev); return ret; } diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c index 4c6d2041260b..94f73bbbc0fd 100644 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -278,7 +278,7 @@ static int ade7854_spi_probe(struct spi_device *spi) struct ade7854_state *st; struct iio_dev *indio_dev; - indio_dev = iio_device_alloc(sizeof(*st)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); @@ -296,8 +296,6 @@ static int ade7854_spi_probe(struct spi_device *spi) ret = ade7854_probe(indio_dev, &spi->dev); - if (ret) - iio_device_free(indio_dev); return ret; } diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c index e8379c0f1173..d620bbd603a3 100644 --- a/drivers/staging/iio/meter/ade7854.c +++ b/drivers/staging/iio/meter/ade7854.c @@ -100,9 +100,9 @@ static ssize_t ade7854_write_8bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); int ret; - long val; + u8 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; ret = st->write_reg_8(dev, this_attr->address, val); @@ -121,9 +121,9 @@ static ssize_t ade7854_write_16bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); int ret; - long val; + u16 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; ret = st->write_reg_16(dev, this_attr->address, val); @@ -142,9 +142,9 @@ static ssize_t ade7854_write_24bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); int ret; - long val; + u32 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou32(buf, 10, &val); if (ret) goto error_ret; ret = st->write_reg_24(dev, this_attr->address, val); @@ -163,9 +163,9 @@ static ssize_t ade7854_write_32bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); int ret; - long val; + u32 val; - ret = strict_strtol(buf, 10, &val); + ret = kstrtou32(buf, 10, &val); if (ret) goto error_ret; ret = st->write_reg_32(dev, this_attr->address, val); @@ -550,7 +550,7 @@ int ade7854_probe(struct iio_dev *indio_dev, struct device *dev) ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; /* Get the device into a sane initial state */ ret = ade7854_initial_setup(indio_dev); @@ -561,9 +561,6 @@ int ade7854_probe(struct iio_dev *indio_dev, struct device *dev) error_unreg_dev: iio_device_unregister(indio_dev); -error_free_dev: - iio_device_free(indio_dev); - return ret; } EXPORT_SYMBOL(ade7854_probe); @@ -571,7 +568,6 @@ EXPORT_SYMBOL(ade7854_probe); int ade7854_remove(struct iio_dev *indio_dev) { iio_device_unregister(indio_dev); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c index 71221161aa6b..62d30179301f 100644 --- a/drivers/staging/iio/resolver/ad2s1200.c +++ b/drivers/staging/iio/resolver/ad2s1200.c @@ -107,16 +107,16 @@ static int ad2s1200_probe(struct spi_device *spi) unsigned short *pins = spi->dev.platform_data; for (pn = 0; pn < AD2S1200_PN; pn++) - if (gpio_request_one(pins[pn], GPIOF_DIR_OUT, DRV_NAME)) { - pr_err("%s: request gpio pin %d failed\n", - DRV_NAME, pins[pn]); - goto error_ret; + ret = devm_gpio_request_one(&spi->dev, pins[pn], GPIOF_DIR_OUT, + DRV_NAME); + if (ret) { + dev_err(&spi->dev, "request gpio pin %d failed\n", + pins[pn]); + return ret; } - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; spi_set_drvdata(spi, indio_dev); st = iio_priv(indio_dev); mutex_init(&st->lock); @@ -133,26 +133,18 @@ static int ad2s1200_probe(struct spi_device *spi) ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; spi->max_speed_hz = AD2S1200_HZ; spi->mode = SPI_MODE_3; spi_setup(spi); return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - for (--pn; pn >= 0; pn--) - gpio_free(pins[pn]); - return ret; } static int ad2s1200_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index dcdadbbcf7e8..6966d5f76648 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -206,10 +206,10 @@ static ssize_t ad2s1210_store_fclkin(struct device *dev, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned long fclkin; + unsigned int fclkin; int ret; - ret = strict_strtoul(buf, 10, &fclkin); + ret = kstrtouint(buf, 10, &fclkin); if (ret) return ret; if (fclkin < AD2S1210_MIN_CLKIN || fclkin > AD2S1210_MAX_CLKIN) { @@ -243,10 +243,10 @@ static ssize_t ad2s1210_store_fexcit(struct device *dev, const char *buf, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned long fexcit; + unsigned int fexcit; int ret; - ret = strict_strtoul(buf, 10, &fexcit); + ret = kstrtouint(buf, 10, &fexcit); if (ret < 0) return ret; if (fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) { @@ -282,11 +282,11 @@ static ssize_t ad2s1210_store_control(struct device *dev, const char *buf, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned long udata; + unsigned char udata; unsigned char data; int ret; - ret = strict_strtoul(buf, 16, &udata); + ret = kstrtou8(buf, 16, &udata); if (ret) return -EINVAL; @@ -337,10 +337,10 @@ static ssize_t ad2s1210_store_resolution(struct device *dev, { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned char data; - unsigned long udata; + unsigned char udata; int ret; - ret = strict_strtoul(buf, 10, &udata); + ret = kstrtou8(buf, 10, &udata); if (ret || udata < 10 || udata > 16) { pr_err("ad2s1210: resolution out of range\n"); return -EINVAL; @@ -438,11 +438,11 @@ static ssize_t ad2s1210_store_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - unsigned long data; + unsigned char data; int ret; struct iio_dev_attr *iattr = to_iio_dev_attr(attr); - ret = strict_strtoul(buf, 10, &data); + ret = kstrtou8(buf, 10, &data); if (ret) return -EINVAL; mutex_lock(&st->lock); @@ -669,16 +669,14 @@ static int ad2s1210_probe(struct spi_device *spi) if (spi->dev.platform_data == NULL) return -EINVAL; - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); st->pdata = spi->dev.platform_data; ret = ad2s1210_setup_gpios(st); if (ret < 0) - goto error_free_dev; + return ret; spi_set_drvdata(spi, indio_dev); @@ -709,9 +707,6 @@ static int ad2s1210_probe(struct spi_device *spi) error_free_gpios: ad2s1210_free_gpios(st); -error_free_dev: - iio_device_free(indio_dev); -error_ret: return ret; } @@ -721,7 +716,6 @@ static int ad2s1210_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ad2s1210_free_gpios(iio_priv(indio_dev)); - iio_device_free(indio_dev); return 0; } diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c index 40b825286d4a..e24c5890652f 100644 --- a/drivers/staging/iio/resolver/ad2s90.c +++ b/drivers/staging/iio/resolver/ad2s90.c @@ -64,11 +64,9 @@ static int ad2s90_probe(struct spi_device *spi) struct ad2s90_state *st; int ret = 0; - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); @@ -83,7 +81,7 @@ static int ad2s90_probe(struct spi_device *spi) ret = iio_device_register(indio_dev); if (ret) - goto error_free_dev; + return ret; /* need 600ns between CS and the first falling edge of SCLK */ spi->max_speed_hz = 830000; @@ -91,17 +89,11 @@ static int ad2s90_probe(struct spi_device *spi) spi_setup(spi); return 0; - -error_free_dev: - iio_device_free(indio_dev); -error_ret: - return ret; } static int ad2s90_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c index 38a158b77b1d..26e1ca0b7800 100644 --- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c +++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c @@ -83,32 +83,28 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, { struct iio_trigger *trig = to_iio_trigger(dev); struct bfin_tmr_state *st = iio_trigger_get_drvdata(trig); - unsigned long val; + unsigned int val; bool enabled; int ret; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtouint(buf, 10, &val); if (ret) - goto error_ret; + return ret; - if (val > 100000) { - ret = -EINVAL; - goto error_ret; - } + if (val > 100000) + return -EINVAL; enabled = get_enabled_gptimers() & st->t->bit; if (enabled) disable_gptimers(st->t->bit); - if (!val) - goto error_ret; + if (val == 0) + return count; val = get_sclk() / val; - if (val <= 4 || val <= st->duty) { - ret = -EINVAL; - goto error_ret; - } + if (val <= 4 || val <= st->duty) + return -EINVAL; set_gptimer_period(st->t->id, val); set_gptimer_pwidth(st->t->id, val - st->duty); @@ -116,8 +112,7 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, if (enabled) enable_gptimers(st->t->bit); -error_ret: - return ret ? ret : count; + return count; } static ssize_t iio_bfin_tmr_frequency_show(struct device *dev, diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 79695974b1d4..48a6afa84088 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -53,10 +53,10 @@ static ssize_t iio_trig_periodic_write_freq(struct device *dev, { struct iio_trigger *trig = to_iio_trigger(dev); struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); - unsigned long val; + int val; int ret; - ret = strict_strtoul(buf, 10, &val); + ret = kstrtoint(buf, 10, &val); if (ret) goto error_ret; diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile index bfaf69378ac2..2c3a9e178fb5 100644 --- a/drivers/staging/imx-drm/Makefile +++ b/drivers/staging/imx-drm/Makefile @@ -8,4 +8,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/ -obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3-crtc.o +obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3-crtc.o ipuv3-plane.o diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO index 9cfa2a7efdc0..6a9da94c9573 100644 --- a/drivers/staging/imx-drm/TODO +++ b/drivers/staging/imx-drm/TODO @@ -9,7 +9,6 @@ TODO: Missing features (not necessarily for moving out of staging): -- Add KMS plane support for CRTC driver - Add i.MX6 HDMI support - Add support for IC (Image converter) - Add support for CSI (CMOS Sensor interface) diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index a2e52a0c53c9..d2fb699c0d1d 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -68,6 +68,11 @@ struct imx_drm_connector { struct module *owner; }; +int imx_drm_crtc_id(struct imx_drm_crtc *crtc) +{ + return crtc->pipe; +} + static void imx_drm_driver_lastclose(struct drm_device *drm) { struct imx_drm_device *imxdrm = drm->dev_private; @@ -110,18 +115,12 @@ int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type, struct imx_drm_crtc *imx_crtc; struct imx_drm_crtc_helper_funcs *helper; - mutex_lock(&imxdrm->mutex); - list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) if (imx_crtc->crtc == crtc) goto found; - mutex_unlock(&imxdrm->mutex); - return -EINVAL; found: - mutex_unlock(&imxdrm->mutex); - helper = &imx_crtc->imx_drm_helper_funcs; if (helper->set_interface_pix_fmt) return helper->set_interface_pix_fmt(crtc, @@ -191,6 +190,18 @@ static void imx_drm_disable_vblank(struct drm_device *drm, int crtc) imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc); } +static void imx_drm_driver_preclose(struct drm_device *drm, + struct drm_file *file) +{ + int i; + + if (!file->is_master) + return; + + for (i = 0; i < 4; i++) + imx_drm_disable_vblank(drm , i); +} + static const struct file_operations imx_drm_driver_fops = { .owner = THIS_MODULE, .open = drm_open, @@ -647,20 +658,14 @@ int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder, struct imx_drm_crtc *imx_crtc; int i = 0; - mutex_lock(&imxdrm->mutex); - list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) { if (imx_crtc->crtc == crtc) goto found; i++; } - mutex_unlock(&imxdrm->mutex); - return -EINVAL; found: - mutex_unlock(&imxdrm->mutex); - return i; } EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id); @@ -774,16 +779,26 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = { }; static struct drm_driver imx_drm_driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM, + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, .load = imx_drm_driver_load, .unload = imx_drm_driver_unload, .lastclose = imx_drm_driver_lastclose, + .preclose = imx_drm_driver_preclose, .gem_free_object = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, .get_vblank_counter = drm_vblank_count, .enable_vblank = imx_drm_enable_vblank, .disable_vblank = imx_drm_disable_vblank, diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h index f2aac91ddf5d..ae90c9c15312 100644 --- a/drivers/staging/imx-drm/imx-drm.h +++ b/drivers/staging/imx-drm/imx-drm.h @@ -14,6 +14,8 @@ struct drm_fbdev_cma; struct drm_framebuffer; struct platform_device; +int imx_drm_crtc_id(struct imx_drm_crtc *crtc); + struct imx_drm_crtc_helper_funcs { int (*enable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc); diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index af733ea48565..926f49339b26 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -421,7 +421,7 @@ static const char *imx_ldb_bit_mappings[] = { [LVDS_BIT_MAP_JEIDA] = "jeida", }; -const int of_get_data_mapping(struct device_node *np) +static const int of_get_data_mapping(struct device_node *np) { const char *bm; int ret, i; @@ -466,8 +466,7 @@ static int imx_ldb_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = - of_match_device(of_match_ptr(imx_ldb_dt_ids), - &pdev->dev); + of_match_device(imx_ldb_dt_ids, &pdev->dev); struct device_node *child; const u8 *edidp; struct imx_ldb *imx_ldb; diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c index 33d6525cf996..59dd4d560ce0 100644 --- a/drivers/staging/imx-drm/imx-tve.c +++ b/drivers/staging/imx-drm/imx-tve.c @@ -696,7 +696,7 @@ static int imx_tve_probe(struct platform_device *pdev) if (val != 0x00100000) { dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n"); return -ENODEV; - }; + } /* disable cable detection for VGA mode */ ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0); diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h index 74c022e2a532..4826b5c0249d 100644 --- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h @@ -97,6 +97,7 @@ void ipu_idmac_put(struct ipuv3_channel *); int ipu_idmac_enable_channel(struct ipuv3_channel *channel); int ipu_idmac_disable_channel(struct ipuv3_channel *channel); +int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms); void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, bool doublebuffer); @@ -283,7 +284,7 @@ int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p, int width); int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *, - struct ipu_rgb *rgb); + const struct ipu_rgb *rgb); static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p, int stride) @@ -303,6 +304,7 @@ int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat); int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, struct ipu_image *image); +enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p, diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index ba464e5d9f12..a0e7fc2f4031 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c @@ -30,6 +30,8 @@ #include <linux/irqdomain.h> #include <linux/of_device.h> +#include <drm/drm_fourcc.h> + #include "imx-ipu-v3.h" #include "ipu-prv.h" @@ -139,7 +141,7 @@ u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs) EXPORT_SYMBOL_GPL(ipu_ch_param_read_field); int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p, - struct ipu_rgb *rgb) + const struct ipu_rgb *rgb) { int bpp = 0, npb = 0, ro, go, bo, to; @@ -282,7 +284,7 @@ void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format, } EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); -static struct ipu_rgb def_rgb_32 = { +static const struct ipu_rgb def_rgb_32 = { .red = { .offset = 16, .length = 8, }, .green = { .offset = 8, .length = 8, }, .blue = { .offset = 0, .length = 8, }, @@ -290,31 +292,31 @@ static struct ipu_rgb def_rgb_32 = { .bits_per_pixel = 32, }; -static struct ipu_rgb def_bgr_32 = { - .red = { .offset = 16, .length = 8, }, +static const struct ipu_rgb def_bgr_32 = { + .red = { .offset = 0, .length = 8, }, .green = { .offset = 8, .length = 8, }, - .blue = { .offset = 0, .length = 8, }, + .blue = { .offset = 16, .length = 8, }, .transp = { .offset = 24, .length = 8, }, .bits_per_pixel = 32, }; -static struct ipu_rgb def_rgb_24 = { - .red = { .offset = 0, .length = 8, }, +static const struct ipu_rgb def_rgb_24 = { + .red = { .offset = 16, .length = 8, }, .green = { .offset = 8, .length = 8, }, - .blue = { .offset = 16, .length = 8, }, + .blue = { .offset = 0, .length = 8, }, .transp = { .offset = 0, .length = 0, }, .bits_per_pixel = 24, }; -static struct ipu_rgb def_bgr_24 = { - .red = { .offset = 16, .length = 8, }, +static const struct ipu_rgb def_bgr_24 = { + .red = { .offset = 0, .length = 8, }, .green = { .offset = 8, .length = 8, }, - .blue = { .offset = 0, .length = 8, }, + .blue = { .offset = 16, .length = 8, }, .transp = { .offset = 0, .length = 0, }, .bits_per_pixel = 24, }; -static struct ipu_rgb def_rgb_16 = { +static const struct ipu_rgb def_rgb_16 = { .red = { .offset = 11, .length = 5, }, .green = { .offset = 5, .length = 6, }, .blue = { .offset = 0, .length = 5, }, @@ -322,6 +324,14 @@ static struct ipu_rgb def_rgb_16 = { .bits_per_pixel = 16, }; +static const struct ipu_rgb def_bgr_16 = { + .red = { .offset = 0, .length = 5, }, + .green = { .offset = 5, .length = 6, }, + .blue = { .offset = 11, .length = 5, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 16, +}; + #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) #define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ (pix->width * (y) / 4) + (x) / 2) @@ -329,17 +339,17 @@ static struct ipu_rgb def_rgb_16 = { (pix->width * pix->height / 4) + \ (pix->width * (y) / 4) + (x) / 2) -int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat) +int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc) { - switch (pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: + switch (drm_fourcc) { + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: /* pix format */ ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2); /* burst size */ ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63); break; - case V4L2_PIX_FMT_UYVY: + case DRM_FORMAT_UYVY: /* bits/pixel */ ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3); /* pix format */ @@ -347,7 +357,7 @@ int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat) /* burst size */ ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31); break; - case V4L2_PIX_FMT_YUYV: + case DRM_FORMAT_YUYV: /* bits/pixel */ ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3); /* pix format */ @@ -355,20 +365,25 @@ int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat) /* burst size */ ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31); break; - case V4L2_PIX_FMT_RGB32: - ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32); + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32); break; - case V4L2_PIX_FMT_RGB565: - ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16); + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32); break; - case V4L2_PIX_FMT_BGR32: - ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32); + case DRM_FORMAT_BGR888: + ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24); break; - case V4L2_PIX_FMT_RGB24: + case DRM_FORMAT_RGB888: ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24); break; - case V4L2_PIX_FMT_BGR24: - ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24); + case DRM_FORMAT_RGB565: + ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16); + break; + case DRM_FORMAT_BGR565: + ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16); break; default: return -EINVAL; @@ -378,6 +393,79 @@ int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat) } EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); +/* + * The V4L2 spec defines packed RGB formats in memory byte order, which from + * point of view of the IPU corresponds to little-endian words with the first + * component in the least significant bits. + * The DRM pixel formats and IPU internal representation are ordered the other + * way around, with the first named component ordered at the most significant + * bits. Further, V4L2 formats are not well defined: + * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html + * We choose the interpretation which matches GStreamer behavior. + */ +static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_RGB565: + /* + * Here we choose the 'corrected' interpretation of RGBP, a + * little-endian 16-bit word with the red component at the most + * significant bits: + * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B + */ + return DRM_FORMAT_RGB565; + case V4L2_PIX_FMT_BGR24: + /* B G R <=> [24:0] R:G:B */ + return DRM_FORMAT_RGB888; + case V4L2_PIX_FMT_RGB24: + /* R G B <=> [24:0] B:G:R */ + return DRM_FORMAT_BGR888; + case V4L2_PIX_FMT_BGR32: + /* B G R A <=> [32:0] A:B:G:R */ + return DRM_FORMAT_XRGB8888; + case V4L2_PIX_FMT_RGB32: + /* R G B A <=> [32:0] A:B:G:R */ + return DRM_FORMAT_XBGR8888; + case V4L2_PIX_FMT_UYVY: + return DRM_FORMAT_UYVY; + case V4L2_PIX_FMT_YUYV: + return DRM_FORMAT_YUYV; + case V4L2_PIX_FMT_YUV420: + return DRM_FORMAT_YUV420; + case V4L2_PIX_FMT_YVU420: + return DRM_FORMAT_YVU420; + } + + return -EINVAL; +} + +enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) +{ + switch (drm_fourcc) { + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + return IPUV3_COLORSPACE_RGB; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + return IPUV3_COLORSPACE_YUV; + default: + return IPUV3_COLORSPACE_UNKNOWN; + } +} +EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace); + int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, struct ipu_image *image) { @@ -392,7 +480,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, image->rect.height); ipu_cpmem_set_stride(cpmem, pix->bytesperline); - ipu_cpmem_set_fmt(cpmem, pix->pixelformat); + ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); switch (pix->pixelformat) { case V4L2_PIX_FMT_YUV420: @@ -610,24 +698,29 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel) } EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel); -int ipu_idmac_disable_channel(struct ipuv3_channel *channel) +int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms) { struct ipu_soc *ipu = channel->ipu; - u32 val; - unsigned long flags; unsigned long timeout; - timeout = jiffies + msecs_to_jiffies(50); + timeout = jiffies + msecs_to_jiffies(ms); while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) & idma_mask(channel->num)) { - if (time_after(jiffies, timeout)) { - dev_warn(ipu->dev, "disabling busy idmac channel %d\n", - channel->num); - break; - } + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; cpu_relax(); } + return 0; +} +EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy); + +int ipu_idmac_disable_channel(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + u32 val; + unsigned long flags; + spin_lock_irqsave(&ipu->lock, flags); /* Disable DMA channel(s) */ @@ -888,7 +981,7 @@ static const struct ipu_platform_reg client_reg[] = { .dc = 5, .dp = IPU_DP_FLOW_SYNC_BG, .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC, - .dma[1] = -EINVAL, + .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC, }, .name = "imx-ipuv3-crtc", }, { diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c index 21bf1c806528..1a6e06d1ebaf 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c @@ -91,6 +91,7 @@ enum ipu_dc_map { IPU_DC_MAP_RGB565, IPU_DC_MAP_GBR24, /* TVEv2 */ IPU_DC_MAP_BGR666, + IPU_DC_MAP_BGR24, }; struct ipu_dc { @@ -152,6 +153,8 @@ static int ipu_pixfmt_to_map(u32 fmt) return IPU_DC_MAP_GBR24; case V4L2_PIX_FMT_BGR666: return IPU_DC_MAP_BGR666; + case V4L2_PIX_FMT_BGR24: + return IPU_DC_MAP_BGR24; default: return -EINVAL; } @@ -395,6 +398,12 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */ ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */ + /* bgr24 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24); + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */ + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */ + return 0; } diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c index 2e97c33b81e7..98070dd8c920 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c @@ -307,13 +307,13 @@ int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, goto out; } - /* Always allocate at least 128*4 bytes (2 slots) */ - if (slots < 2) - slots = 2; - /* For the MEM_BG channel, first try to allocate twice the slots */ if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC) segment = dmfc_find_slots(priv, slots * 2); + else if (slots < 2) + /* Always allocate at least 128*4 bytes (2 slots) */ + slots = 2; + if (segment >= 0) slots *= 2; else diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index 6fd37a7453e9..f1112dfa6bf6 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c @@ -25,29 +25,25 @@ #include <drm/drm_crtc_helper.h> #include <linux/fb.h> #include <linux/clk.h> +#include <linux/errno.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> #include "ipu-v3/imx-ipu-v3.h" #include "imx-drm.h" +#include "ipuv3-plane.h" #define DRIVER_DESC "i.MX IPUv3 Graphics" -struct ipu_framebuffer { - struct drm_framebuffer base; - void *virt; - dma_addr_t phys; - size_t len; -}; - struct ipu_crtc { struct device *dev; struct drm_crtc base; struct imx_drm_crtc *imx_crtc; - struct ipuv3_channel *ipu_ch; + + /* plane[0] is the full plane, plane[1] is the partial plane */ + struct ipu_plane *plane[2]; + struct ipu_dc *dc; - struct ipu_dp *dp; - struct dmfc_channel *dmfc; struct ipu_di *di; int enabled; struct drm_pending_vblank_event *page_flip_event; @@ -61,35 +57,14 @@ struct ipu_crtc { #define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base) -static int calc_vref(struct drm_display_mode *mode) -{ - unsigned long htotal, vtotal; - - htotal = mode->htotal; - vtotal = mode->vtotal; - - if (!htotal || !vtotal) - return 60; - - return mode->clock * 1000 / vtotal / htotal; -} - -static int calc_bandwidth(struct drm_display_mode *mode, unsigned int vref) -{ - return mode->hdisplay * mode->vdisplay * vref; -} - static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) { if (ipu_crtc->enabled) return; ipu_di_enable(ipu_crtc->di); - ipu_dmfc_enable_channel(ipu_crtc->dmfc); - ipu_idmac_enable_channel(ipu_crtc->ipu_ch); ipu_dc_enable_channel(ipu_crtc->dc); - if (ipu_crtc->dp) - ipu_dp_enable_channel(ipu_crtc->dp); + ipu_plane_enable(ipu_crtc->plane[0]); ipu_crtc->enabled = 1; } @@ -99,11 +74,8 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) if (!ipu_crtc->enabled) return; - if (ipu_crtc->dp) - ipu_dp_disable_channel(ipu_crtc->dp); + ipu_plane_disable(ipu_crtc->plane[0]); ipu_dc_disable_channel(ipu_crtc->dc); - ipu_idmac_disable_channel(ipu_crtc->ipu_ch); - ipu_dmfc_disable_channel(ipu_crtc->dmfc); ipu_di_disable(ipu_crtc->di); ipu_crtc->enabled = 0; @@ -159,33 +131,6 @@ static const struct drm_crtc_funcs ipu_crtc_funcs = { .page_flip = ipu_page_flip, }; -static int ipu_drm_set_base(struct drm_crtc *crtc, int x, int y) -{ - struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - struct drm_gem_cma_object *cma_obj; - struct drm_framebuffer *fb = crtc->fb; - unsigned long phys; - - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { - DRM_LOG_KMS("entry is null.\n"); - return -EFAULT; - } - - phys = cma_obj->paddr; - phys += x * (fb->bits_per_pixel >> 3); - phys += y * fb->pitches[0]; - - dev_dbg(ipu_crtc->dev, "%s: phys: 0x%lx\n", __func__, phys); - dev_dbg(ipu_crtc->dev, "%s: xy: %dx%d\n", __func__, x, y); - - ipu_cpmem_set_stride(ipu_get_cpmem(ipu_crtc->ipu_ch), fb->pitches[0]); - ipu_cpmem_set_buffer(ipu_get_cpmem(ipu_crtc->ipu_ch), - 0, phys); - - return 0; -} - static int ipu_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *orig_mode, struct drm_display_mode *mode, @@ -193,41 +138,15 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - struct drm_framebuffer *fb = ipu_crtc->base.fb; int ret; struct ipu_di_signal_cfg sig_cfg = {}; u32 out_pixel_fmt; - struct ipu_ch_param __iomem *cpmem = ipu_get_cpmem(ipu_crtc->ipu_ch); - int bpp; - u32 v4l2_fmt; dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, mode->hdisplay); dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, mode->vdisplay); - ipu_ch_param_zero(cpmem); - - switch (fb->pixel_format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: - v4l2_fmt = V4L2_PIX_FMT_RGB32; - bpp = 32; - break; - case DRM_FORMAT_RGB565: - v4l2_fmt = V4L2_PIX_FMT_RGB565; - bpp = 16; - break; - case DRM_FORMAT_RGB888: - v4l2_fmt = V4L2_PIX_FMT_RGB24; - bpp = 24; - break; - default: - dev_err(ipu_crtc->dev, "unsupported pixel format 0x%08x\n", - fb->pixel_format); - return -EINVAL; - } - out_pixel_fmt = ipu_crtc->interface_pix_fmt; if (mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -257,18 +176,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; - if (ipu_crtc->dp) { - ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB, - IPUV3_COLORSPACE_RGB); - if (ret) { - dev_err(ipu_crtc->dev, - "initializing display processor failed with %d\n", - ret); - return ret; - } - ipu_dp_set_global_alpha(ipu_crtc->dp, 1, 0, 1); - } - ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced, out_pixel_fmt, mode->hdisplay); if (ret) { @@ -285,30 +192,9 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, return ret; } - ipu_cpmem_set_resolution(cpmem, mode->hdisplay, mode->vdisplay); - ipu_cpmem_set_fmt(cpmem, v4l2_fmt); - ipu_cpmem_set_high_priority(ipu_crtc->ipu_ch); - - ret = ipu_dmfc_init_channel(ipu_crtc->dmfc, mode->hdisplay); - if (ret) { - dev_err(ipu_crtc->dev, - "initializing dmfc channel failed with %d\n", - ret); - return ret; - } - - ret = ipu_dmfc_alloc_bandwidth(ipu_crtc->dmfc, - calc_bandwidth(mode, calc_vref(mode)), 64); - if (ret) { - dev_err(ipu_crtc->dev, - "allocating dmfc bandwidth failed with %d\n", - ret); - return ret; - } - - ipu_drm_set_base(crtc, x, y); - - return 0; + return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb, + 0, 0, mode->hdisplay, mode->vdisplay, + x, y, mode->hdisplay, mode->vdisplay); } static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) @@ -332,7 +218,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id) if (ipu_crtc->newfb) { ipu_crtc->newfb = NULL; - ipu_drm_set_base(&ipu_crtc->base, 0, 0); + ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb, 0, 0); ipu_crtc_handle_pageflip(ipu_crtc); } @@ -370,10 +256,6 @@ static struct drm_crtc_helper_funcs ipu_helper_funcs = { static int ipu_enable_vblank(struct drm_crtc *crtc) { - struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - - enable_irq(ipu_crtc->irq); - return 0; } @@ -381,7 +263,8 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - disable_irq(ipu_crtc->irq); + ipu_crtc->page_flip_event = NULL; + ipu_crtc->newfb = NULL; } static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type, @@ -418,12 +301,8 @@ static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = { static void ipu_put_resources(struct ipu_crtc *ipu_crtc) { - if (!IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) - ipu_idmac_put(ipu_crtc->ipu_ch); - if (!IS_ERR_OR_NULL(ipu_crtc->dmfc)) - ipu_dmfc_put(ipu_crtc->dmfc); - if (!IS_ERR_OR_NULL(ipu_crtc->dp)) - ipu_dp_put(ipu_crtc->dp); + if (!IS_ERR_OR_NULL(ipu_crtc->dc)) + ipu_dc_put(ipu_crtc->dc); if (!IS_ERR_OR_NULL(ipu_crtc->di)) ipu_di_put(ipu_crtc->di); } @@ -434,32 +313,12 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc, struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); int ret; - ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]); - if (IS_ERR(ipu_crtc->ipu_ch)) { - ret = PTR_ERR(ipu_crtc->ipu_ch); - goto err_out; - } - ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc); if (IS_ERR(ipu_crtc->dc)) { ret = PTR_ERR(ipu_crtc->dc); goto err_out; } - ipu_crtc->dmfc = ipu_dmfc_get(ipu, pdata->dma[0]); - if (IS_ERR(ipu_crtc->dmfc)) { - ret = PTR_ERR(ipu_crtc->dmfc); - goto err_out; - } - - if (pdata->dp >= 0) { - ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp); - if (IS_ERR(ipu_crtc->dp)) { - ret = PTR_ERR(ipu_crtc->dp); - goto err_out; - } - } - ipu_crtc->di = ipu_di_get(ipu, pdata->di); if (IS_ERR(ipu_crtc->di)) { ret = PTR_ERR(ipu_crtc->di); @@ -477,7 +336,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, struct ipu_client_platformdata *pdata) { struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); + int dp = -EINVAL; int ret; + int id; ret = ipu_get_resources(ipu_crtc, pdata); if (ret) { @@ -495,19 +356,42 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, goto err_put_resources; } - ipu_crtc->irq = ipu_idmac_channel_irq(ipu, ipu_crtc->ipu_ch, - IPU_IRQ_EOF); + if (pdata->dp >= 0) + dp = IPU_DP_FLOW_SYNC_BG; + id = imx_drm_crtc_id(ipu_crtc->imx_crtc); + ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu, + pdata->dma[0], dp, BIT(id), true); + ret = ipu_plane_get_resources(ipu_crtc->plane[0]); + if (ret) { + dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n", + ret); + goto err_remove_crtc; + } + + /* If this crtc is using the DP, add an overlay plane */ + if (pdata->dp >= 0 && pdata->dma[1] > 0) { + ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu, + pdata->dma[1], + IPU_DP_FLOW_SYNC_FG, + BIT(id), false); + if (IS_ERR(ipu_crtc->plane[1])) + ipu_crtc->plane[1] = NULL; + } + + ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]); ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0, "imx_drm", ipu_crtc); if (ret < 0) { dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); - goto err_put_resources; + goto err_put_plane_res; } - disable_irq(ipu_crtc->irq); - return 0; +err_put_plane_res: + ipu_plane_put_resources(ipu_crtc->plane[0]); +err_remove_crtc: + imx_drm_remove_crtc(ipu_crtc->imx_crtc); err_put_resources: ipu_put_resources(ipu_crtc); @@ -546,6 +430,7 @@ static int ipu_drm_remove(struct platform_device *pdev) imx_drm_remove_crtc(ipu_crtc->imx_crtc); + ipu_plane_put_resources(ipu_crtc->plane[0]); ipu_put_resources(ipu_crtc); return 0; diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c new file mode 100644 index 000000000000..d97454a0dffd --- /dev/null +++ b/drivers/staging/imx-drm/ipuv3-plane.c @@ -0,0 +1,375 @@ +/* + * i.MX IPUv3 DP Overlay Planes + * + * Copyright (C) 2013 Philipp Zabel, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <drm/drmP.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> + +#include "ipu-v3/imx-ipu-v3.h" +#include "ipuv3-plane.h" + +#define to_ipu_plane(x) container_of(x, struct ipu_plane, base) + +static const uint32_t ipu_plane_formats[] = { + DRM_FORMAT_XRGB1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_YUV420, + DRM_FORMAT_YVU420, +}; + +int ipu_plane_irq(struct ipu_plane *ipu_plane) +{ + return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch, + IPU_IRQ_EOF); +} + +static int calc_vref(struct drm_display_mode *mode) +{ + unsigned long htotal, vtotal; + + htotal = mode->htotal; + vtotal = mode->vtotal; + + if (!htotal || !vtotal) + return 60; + + return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal); +} + +static inline int calc_bandwidth(int width, int height, unsigned int vref) +{ + return width * height * vref; +} + +int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, + int x, int y) +{ + struct ipu_ch_param __iomem *cpmem; + struct drm_gem_cma_object *cma_obj; + + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + DRM_LOG_KMS("entry is null.\n"); + return -EFAULT; + } + + dev_dbg(ipu_plane->base.dev->dev, "phys = 0x%x, x = %d, y = %d", + cma_obj->paddr, x, y); + + cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); + ipu_cpmem_set_stride(cpmem, fb->pitches[0]); + ipu_cpmem_set_buffer(cpmem, 0, cma_obj->paddr + fb->offsets[0] + + fb->pitches[0] * y + x); + + return 0; +} + +int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct ipu_ch_param __iomem *cpmem; + struct device *dev = ipu_plane->base.dev->dev; + int ret; + + /* no scaling */ + if (src_w != crtc_w || src_h != crtc_h) + return -EINVAL; + + /* clip to crtc bounds */ + if (crtc_x < 0) { + if (-crtc_x > crtc_w) + return -EINVAL; + src_x += -crtc_x; + src_w -= -crtc_x; + crtc_w -= -crtc_x; + crtc_x = 0; + } + if (crtc_y < 0) { + if (-crtc_y > crtc_h) + return -EINVAL; + src_y += -crtc_y; + src_h -= -crtc_y; + crtc_h -= -crtc_y; + crtc_y = 0; + } + if (crtc_x + crtc_w > mode->hdisplay) { + if (crtc_x > mode->hdisplay) + return -EINVAL; + crtc_w = mode->hdisplay - crtc_x; + src_w = crtc_w; + } + if (crtc_y + crtc_h > mode->vdisplay) { + if (crtc_y > mode->vdisplay) + return -EINVAL; + crtc_h = mode->vdisplay - crtc_y; + src_h = crtc_h; + } + /* full plane minimum width is 13 pixels */ + if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG)) + return -EINVAL; + if (crtc_h < 2) + return -EINVAL; + + switch (ipu_plane->dp_flow) { + case IPU_DP_FLOW_SYNC_BG: + ret = ipu_dp_setup_channel(ipu_plane->dp, + IPUV3_COLORSPACE_RGB, + IPUV3_COLORSPACE_RGB); + if (ret) { + dev_err(dev, + "initializing display processor failed with %d\n", + ret); + return ret; + } + ipu_dp_set_global_alpha(ipu_plane->dp, 1, 0, 1); + break; + case IPU_DP_FLOW_SYNC_FG: + ipu_dp_setup_channel(ipu_plane->dp, + ipu_drm_fourcc_to_colorspace(fb->pixel_format), + IPUV3_COLORSPACE_UNKNOWN); + ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y); + break; + } + + ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w); + if (ret) { + dev_err(dev, "initializing dmfc channel failed with %d\n", ret); + return ret; + } + + ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc, + calc_bandwidth(crtc_w, crtc_h, + calc_vref(mode)), 64); + if (ret) { + dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret); + return ret; + } + + cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); + ipu_ch_param_zero(cpmem); + ipu_cpmem_set_resolution(cpmem, src_w, src_h); + ret = ipu_cpmem_set_fmt(cpmem, fb->pixel_format); + if (ret < 0) { + dev_err(dev, "unsupported pixel format 0x%08x\n", + fb->pixel_format); + return ret; + } + ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); + + ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y); + if (ret < 0) + return ret; + + return 0; +} + +void ipu_plane_put_resources(struct ipu_plane *ipu_plane) +{ + if (!IS_ERR_OR_NULL(ipu_plane->dp)) + ipu_dp_put(ipu_plane->dp); + if (!IS_ERR_OR_NULL(ipu_plane->dmfc)) + ipu_dmfc_put(ipu_plane->dmfc); + if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch)) + ipu_idmac_put(ipu_plane->ipu_ch); +} + +int ipu_plane_get_resources(struct ipu_plane *ipu_plane) +{ + int ret; + + ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma); + if (IS_ERR(ipu_plane->ipu_ch)) { + ret = PTR_ERR(ipu_plane->ipu_ch); + DRM_ERROR("failed to get idmac channel: %d\n", ret); + return ret; + } + + ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma); + if (IS_ERR(ipu_plane->dmfc)) { + ret = PTR_ERR(ipu_plane->dmfc); + DRM_ERROR("failed to get dmfc: ret %d\n", ret); + goto err_out; + } + + if (ipu_plane->dp_flow >= 0) { + ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow); + if (IS_ERR(ipu_plane->dp)) { + ret = PTR_ERR(ipu_plane->dp); + DRM_ERROR("failed to get dp flow: %d\n", ret); + goto err_out; + } + } + + return 0; +err_out: + ipu_plane_put_resources(ipu_plane); + + return ret; +} + +void ipu_plane_enable(struct ipu_plane *ipu_plane) +{ + ipu_dmfc_enable_channel(ipu_plane->dmfc); + ipu_idmac_enable_channel(ipu_plane->ipu_ch); + if (ipu_plane->dp) + ipu_dp_enable_channel(ipu_plane->dp); + + ipu_plane->enabled = true; +} + +void ipu_plane_disable(struct ipu_plane *ipu_plane) +{ + ipu_plane->enabled = false; + + ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); + + if (ipu_plane->dp) + ipu_dp_disable_channel(ipu_plane->dp); + ipu_idmac_disable_channel(ipu_plane->ipu_ch); + ipu_dmfc_disable_channel(ipu_plane->dmfc); +} + +static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode) +{ + bool enable; + + DRM_DEBUG_KMS("mode = %d", mode); + + enable = (mode == DRM_MODE_DPMS_ON); + + if (enable == ipu_plane->enabled) + return; + + if (enable) { + ipu_plane_enable(ipu_plane); + } else { + ipu_plane_disable(ipu_plane); + + ipu_idmac_put(ipu_plane->ipu_ch); + ipu_dmfc_put(ipu_plane->dmfc); + ipu_dp_put(ipu_plane->dp); + } +} + +/* + * drm_plane API + */ + +static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct ipu_plane *ipu_plane = to_ipu_plane(plane); + int ret = 0; + + DRM_DEBUG_KMS("plane - %p\n", plane); + + if (!ipu_plane->enabled) + ret = ipu_plane_get_resources(ipu_plane); + if (ret < 0) + return ret; + + ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16); + if (ret < 0) { + ipu_plane_put_resources(ipu_plane); + return ret; + } + + if (crtc != plane->crtc) + dev_info(plane->dev->dev, "crtc change: %p -> %p\n", + plane->crtc, crtc); + plane->crtc = crtc; + + ipu_plane_dpms(ipu_plane, DRM_MODE_DPMS_ON); + + return 0; +} + +static int ipu_disable_plane(struct drm_plane *plane) +{ + struct ipu_plane *ipu_plane = to_ipu_plane(plane); + + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); + + ipu_plane_dpms(ipu_plane, DRM_MODE_DPMS_OFF); + + ipu_plane_put_resources(ipu_plane); + + return 0; +} + +static void ipu_plane_destroy(struct drm_plane *plane) +{ + struct ipu_plane *ipu_plane = to_ipu_plane(plane); + + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); + + ipu_disable_plane(plane); + drm_plane_cleanup(plane); + kfree(ipu_plane); +} + +static struct drm_plane_funcs ipu_plane_funcs = { + .update_plane = ipu_update_plane, + .disable_plane = ipu_disable_plane, + .destroy = ipu_plane_destroy, +}; + +struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, + int dma, int dp, unsigned int possible_crtcs, + bool priv) +{ + struct ipu_plane *ipu_plane; + int ret; + + DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n", + dma, dp, possible_crtcs); + + ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL); + if (!ipu_plane) { + DRM_ERROR("failed to allocate plane\n"); + return ERR_PTR(-ENOMEM); + } + + ipu_plane->ipu = ipu; + ipu_plane->dma = dma; + ipu_plane->dp_flow = dp; + + ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs, + &ipu_plane_funcs, ipu_plane_formats, + ARRAY_SIZE(ipu_plane_formats), + priv); + if (ret) { + DRM_ERROR("failed to initialize plane\n"); + kfree(ipu_plane); + return ERR_PTR(ret); + } + + return ipu_plane; +} diff --git a/drivers/staging/imx-drm/ipuv3-plane.h b/drivers/staging/imx-drm/ipuv3-plane.h new file mode 100644 index 000000000000..c0aae5bcb5d4 --- /dev/null +++ b/drivers/staging/imx-drm/ipuv3-plane.h @@ -0,0 +1,55 @@ +#ifndef __IPUV3_PLANE_H__ +#define __IPUV3_PLANE_H__ + +#include <drm/drm_crtc.h> /* drm_plane */ + +struct drm_plane; +struct drm_device; +struct ipu_soc; +struct drm_crtc; +struct drm_framebuffer; + +struct ipuv3_channel; +struct dmfc_channel; +struct ipu_dp; + +struct ipu_plane { + struct drm_plane base; + + struct ipu_soc *ipu; + struct ipuv3_channel *ipu_ch; + struct dmfc_channel *dmfc; + struct ipu_dp *dp; + + int dma; + int dp_flow; + + int x; + int y; + + bool enabled; +}; + +struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, + int dma, int dp, unsigned int possible_crtcs, + bool priv); + +/* Init IDMAC, DMFC, DP */ +int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, uint32_t src_w, + uint32_t src_h); + +void ipu_plane_enable(struct ipu_plane *plane); +void ipu_plane_disable(struct ipu_plane *plane); +int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb, + int x, int y); + +int ipu_plane_get_resources(struct ipu_plane *plane); +void ipu_plane_put_resources(struct ipu_plane *plane); + +int ipu_plane_irq(struct ipu_plane *plane); + +#endif diff --git a/drivers/staging/keucr/usb.c b/drivers/staging/keucr/usb.c index ddd2e7390b46..a84ee6303368 100644 --- a/drivers/staging/keucr/usb.c +++ b/drivers/staging/keucr/usb.c @@ -604,9 +604,7 @@ static int eucr_probe(struct usb_interface *intf, if (!(MiscReg03 & 0x02)) { result = -ENODEV; quiesce_and_remove_host(us); - pr_info("keucr: The driver only supports SM/MS card. " - "To use SD card, " - "please build driver/usb/storage/ums-eneub6250.ko\n"); + pr_info("keucr: The driver only supports SM/MS card. To use SD card, please build driver/usb/storage/ums-eneub6250.ko\n"); goto BadDevice; } diff --git a/drivers/staging/ktap/Kconfig b/drivers/staging/ktap/Kconfig new file mode 100644 index 000000000000..21f8d2ed03b9 --- /dev/null +++ b/drivers/staging/ktap/Kconfig @@ -0,0 +1,21 @@ +config KTAP + tristate "a programable dynamic tracing tool for Linux" + depends on PERF_EVENTS && EVENT_TRACING + default n + help + ktap is a new script-based dynamic tracing tool for Linux, + it uses a scripting language and lets users trace the + Linux kernel dynamically. ktap is designed to give + operational insights with interoperability that allow + users to tune, troubleshoot and extend kernel and application. + It's similar with Linux Systemtap and Solaris Dtrace. + + ktap have different design principles from Linux mainstream + dynamic tracing language in that it's based on bytecode, + so it doesn't depend upon GCC, doesn't require compiling + kernel module for each script, safe to use in production + environment, fulfilling the embedded ecosystem's tracing needs. + + See ktap tutorial for more information: + http://www.ktap.org/doc/tutorial.html + diff --git a/drivers/staging/ktap/Makefile b/drivers/staging/ktap/Makefile new file mode 100644 index 000000000000..e2e54baf36d9 --- /dev/null +++ b/drivers/staging/ktap/Makefile @@ -0,0 +1,101 @@ + +# Do not instrument the tracer itself: +ifdef CONFIG_FUNCTION_TRACER +ORIG_CFLAGS := $(KBUILD_CFLAGS) +KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS)) +endif + +all: mod ktap + +INTP = interpreter + +LIBDIR = $(INTP)/library + +LIB_OBJS += $(LIBDIR)/baselib.o $(LIBDIR)/kdebug.o $(LIBDIR)/timer.o \ + $(LIBDIR)/ansilib.o + +INTP_OBJS += $(INTP)/ktap.o $(INTP)/loader.o $(INTP)/object.o \ + $(INTP)/tstring.o $(INTP)/table.o $(INTP)/vm.o \ + $(INTP)/opcode.o $(INTP)/strfmt.o $(INTP)/transport.o \ + $(LIB_OBJS) + +obj-m += ktapvm.o +ktapvm-y := $(INTP_OBJS) + +KVERSION ?= $(shell uname -r) +KERNEL_SRC ?= /lib/modules/$(KVERSION)/build +mod: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules + +modules_install: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules_install + +KTAPC_CFLAGS = -Wall -O2 + +UDIR = userspace + +$(UDIR)/lex.o: $(UDIR)/lex.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/parser.o: $(UDIR)/parser.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/code.o: $(UDIR)/code.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/dump.o: $(UDIR)/dump.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/main.o: $(UDIR)/main.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/util.o: $(UDIR)/util.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/ktapio.o: $(UDIR)/ktapio.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/eventdef.o: $(UDIR)/eventdef.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/opcode.o: $(INTP)/opcode.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/table.o: $(INTP)/table.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/tstring.o: $(INTP)/tstring.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< +$(UDIR)/object.o: $(INTP)/object.c + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< + +KTAPOBJS = +KTAPOBJS += $(UDIR)/lex.o +KTAPOBJS += $(UDIR)/parser.o +KTAPOBJS += $(UDIR)/code.o +KTAPOBJS += $(UDIR)/dump.o +KTAPOBJS += $(UDIR)/main.o +KTAPOBJS += $(UDIR)/util.o +KTAPOBJS += $(UDIR)/ktapio.o +KTAPOBJS += $(UDIR)/eventdef.o +KTAPOBJS += $(UDIR)/opcode.o +KTAPOBJS += $(UDIR)/table.o +KTAPOBJS += $(UDIR)/tstring.o +KTAPOBJS += $(UDIR)/object.o + +ktap: $(KTAPOBJS) + $(QUIET_LINK)$(CC) $(KTAPC_CFLAGS) -o $@ $(KTAPOBJS) -lpthread + +KMISC := /lib/modules/$(KVERSION)/ktapvm/ + +install: mod ktap + install -d $(KMISC) + install -m 644 -c *.ko /lib/modules/$(KVERSION)/ktapvm/ + /sbin/depmod -a + +load: + insmod ktapvm.ko + +unload: + rmmod ktapvm + +test: FORCE + cd test; sh ./run_test.sh; cd - + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean + $(RM) ktap + +PHONY += FORCE +FORCE: + diff --git a/drivers/staging/ktap/README.md b/drivers/staging/ktap/README.md new file mode 100644 index 000000000000..c8ddd5fa66c6 --- /dev/null +++ b/drivers/staging/ktap/README.md @@ -0,0 +1,144 @@ +# ktap + +A New Scripting Dynamic Tracing Tool For Linux +[www.ktap.org][homepage] + +ktap is a new scripting dynamic tracing tool for Linux, +it uses a scripting language and lets users trace the Linux kernel dynamically. +ktap is designed to give operational insights with interoperability +that allows users to tune, troubleshoot and extend kernel and application. +It's similar with Linux Systemtap and Solaris Dtrace. + +ktap have different design principles from Linux mainstream dynamic tracing +language in that it's based on bytecode, so it doesn't depend upon GCC, +doesn't require compiling kernel module for each script, safe to use in +production environment, fulfilling the embedded ecosystem's tracing needs. + +More information can be found at [ktap homepage][homepage]. + +[homepage]: http://www.ktap.org + +## Highlights + + * simple but powerful scripting language + * register based interpreter (heavily optimized) in Linux kernel + * small and lightweight (6KLOC of interpreter) + * not depend on gcc for each script running + * easy to use in embedded environment without debugging info + * support for tracepoint, kprobe, uprobe, function trace, timer, and more + * supported in x86, arm, ppc, mips + * safety in sandbox + +## Building & Running + +1. Clone ktap from github + + $ git clone http://github.com/ktap/ktap.git + +2. Compiling ktap + + $ cd ktap + $ make #generate ktapvm kernel module and ktap binary + +3. Load ktapvm kernel module(make sure debugfs mounted) + + $ make load #need to be root or have sudo access + +4. Running ktap + + $ ./ktap scripts/helloworld.kp + + +## Examples + +1. simplest one-liner command to enable all tracepoints + + ktap -e "trace *:* { print(argevent) }" + +2. syscall tracing on target process + + ktap -e "trace syscalls:* { print(argevent) }" -- ls + +3. function tracing + + ktap -e "trace ftrace:function { print(argevent) }" + + ktap -e "trace ftrace:function /ip==mutex*/ { print(argevent) }" + +4. simple syscall tracing + + trace syscalls:* { + print(cpu(), pid(), execname(), argevent) + } + +5. syscall tracing in histogram style + + s = {} + + trace syscalls:sys_enter_* { + s[argname] += 1 + } + + trace_end { + histogram(s) + } + +6. kprobe tracing + + trace probe:do_sys_open dfd=%di fname=%dx flags=%cx mode=+4($stack) { + print("entry:", execname(), argevent) + } + + trace probe:do_sys_open%return fd=$retval { + print("exit:", execname(), argevent) + } + +7. uprobe tracing + + trace probe:/lib/libc.so.6:0x000773c0 { + print("entry:", execname(), argevent) + } + + trace probe:/lib/libc.so.6:0x000773c0%return { + print("exit:", execname(), argevent) + } + +8. timer + + tick-1ms { + printf("time fired on one cpu\n"); + } + + profile-2s { + printf("time fired on every cpu\n"); + } + +More sample scripts can be found at scripts/ directory. + +## Mailing list + +ktap@freelists.org +You can subscribe to ktap mailing list at link (subscribe before posting): +http://www.freelists.org/list/ktap + + +## Copyright and License + +ktap is licensed under GPL v2 + +Copyright (C) 2012-2013, Jovi Zhangwei <jovi.zhangwei@gmail.com>. +All rights reserved. + + +## Contribution + +ktap is still under active development, so contributions are welcome. +You are encouraged to report bugs, provide feedback, send feature request, +or hack on it. + + +## See More + +More info can be found at [documentation][tutorial] +[tutorial]: http://www.ktap.org/doc/tutorial.html + diff --git a/drivers/staging/ktap/doc/tutorial.md b/drivers/staging/ktap/doc/tutorial.md new file mode 100644 index 000000000000..3c32ce77a731 --- /dev/null +++ b/drivers/staging/ktap/doc/tutorial.md @@ -0,0 +1,552 @@ +% The ktap Tutorial + +# Introduction + +ktap is a new scripting dynamic tracing tool for linux + +ktap is a new scripting dynamic tracing tool for Linux, +it uses a scripting language and lets users trace the Linux kernel dynamically. +ktap is designed to give operational insights with interoperability +that allows users to tune, troubleshoot and extend kernel and application. +It's similar with Linux Systemtap and Solaris Dtrace. + +ktap have different design principles from Linux mainstream dynamic tracing +language in that it's based on bytecode, so it doesn't depend upon GCC, +doesn't require compiling kernel module for each script, safe to use in +production environment, fulfilling the embedded ecosystem's tracing needs. + +Highlights features: + +* simple but powerful scripting language +* register based interpreter (heavily optimized) in Linux kernel +* small and lightweight (6KLOC of interpreter) +* not depend on gcc for each script running +* easy to use in embedded environment without debugging info +* support for tracepoint, kprobe, uprobe, function trace, timer, and more +* supported in x86, arm, ppc, mips +* safety in sandbox + + +# Getting started + +Requirements + +* Linux 3.1 or later(Need some kernel patches for kernel earlier than 3.1) +* CONFIG_EVENT_TRACING enabled +* CONFIG_PERF_EVENTS enabled +* CONFIG_DEBUG_FS enabled + (make sure debugfs mounted before insmod ktapvm + mount debugfs: mount -t debugfs none /sys/kernel/debug/) + +Note that those configuration is always enabled in Linux distribution, +like REHL, Fedora, Ubuntu, etc. + +1. Clone ktap from github + + $ git clone http://github.com/ktap/ktap.git + +2. Compiling ktap + + $ cd ktap + $ make #generate ktapvm kernel module and ktap binary + +3. Load ktapvm kernel module(make sure debugfs mounted) + + $ make load #need to be root or have sudo access + +4. Running ktap + + $ ./ktap scripts/helloworld.kp + + +# Language basics + +## Syntax basics + +ktap's syntax is design on the mind of C language syntax friendly, +to make it easy scripting by kernel developer. + +1. Variable declaration +The biggest syntax differences with C is that ktap is a dynamic typed +language, so you won't need add any variable type declaration, just +use the variable. + +2. function +All functions in ktap should use keyword "function" declaration + +3. comments +The comments of ktap is starting from '#', long comments doesn't support now. + +4. others +Don't need place any ';' at the ending of statement in ktap. +ktap use free syntax style, so you can choose to use the ';' or not. + +ktap use nil as NULL, the result of any number operate on nil is nil. + +ktap don't have array structure, also don't have any pointer operation. + +## Control structures + +ktap if/else is same as C language. + +There have two method of for-loop in ktap: + + for (i = init, limit, step) { body } + +this is same as below in C: + + for (i = init; i < limit; i += step) { body } + +The next for-loop method is: + + for (k, v in pairs(t)) { body } # looping all elements of table + +Note that ktap don't have "continue" keyword, but C does. + +## Date structures + +Associative array is heavily used in ktap, it's also called by table. + +table declaration: + + t = {} + +how to use table: + + t[1] = 1 + t[1] = "xxx" + t["key"] = 10 + t["key"] = "value" + + for (k, v in pairs(t)) { body } # looping all elements of table + + +# Built in functions and librarys + +## Built in functions + +**print (...)** +Receives any number of arguments, and prints their values, +print is not intended for formatted output, but only as a +quick way to show a value, typically for debugging. +For formatted output, use printf. + +**printf (fmt, ...)** +Similar with C printf, use for format string output. + +**pairs (t)** +Returns three values: the next function, the table t, and nil, +so that the construction +for (k,v in pairs(t)) { body } +will iterate over all key-value pairs of table t. + +**len (t) /len (s)** +If the argument is string, return length of string, +if the argument is table, return counts of table pairs. + +**in_interrupt ()** +checking is context is interrupt context + +**exit ()** +quit ktap executing, similar with exit syscall + +**pid ()** +return current process pid + +**execname ()** +return current process exec name string + +**cpu ()** +return current cpu id + +**arch ()** +return machine architecture, like x86, arm, etc. + +**kernel_v ()** +return Linux kernel version string, like 3.9, etc. + +**user_string (addr)** +Receive userspace address, read string from userspace, return string. + +**histogram (t)** +Receive table, output table histogram to user. + +**curr_task_info (offset, fetch_bytes)** +fetch value in field offset of task_struct structure, argument fetch_bytes +could be 4 or 8, if fetch_bytes is not given, default is 4. + +user may need to get field offset by gdb, for example: +gdb vmlinux +(gdb)p &(((struct task_struct *)0).prio) + +**print_backtrace ()** +print current task stack info + + +## Librarys + +### Kdebug Library + +**kdebug.probe_by_id (event_ids, eventfun)** + +This function is underly representation of high level tracing primitive. +event_ids is the id of all events, it's read from +/sys/kernel/debug/tracing/events/$SYS/$EVENT/id + +for multi-events tracing, the event_ids is concatenation of all id, for example: + "2 3 4", seperated by blank space. + +The second argument in above examples is a function: +function eventfun () { action } + + +**kdebug.probe_end (endfunc)** + +This function is used for invoking a function when tracing end, it will wait +until user press CTRL+C to stop tracing, then ktap will call endfunc function, +user could show tracing results in that function, or do other things. + + +### Timer Library + + + +# Linux tracing basics + +tracepoints, probe, timer +filters +above explaintion +Ring buffer + +# Tracing semantics in ktap + +## Tracing block + +**trace EVENTDEF /FILTER/ { ACTION }** + +This is the basic tracing block for ktap, you need to use a specific EVENTDEF +string, and own event function. + +EVENTDEF is compatible with perf(see perf-list), with glob match, for example: + + syscalls:* trace all syscalls events + syscalls:sys_enter_* trace all syscalls entry events + kmem:* trace all kmem related events + sched:* trace all sched related events + *:* trace all tracepoints in system. + +All events are based on: /sys/kernel/debug/tracing/events/$SYS/$EVENT + +**trace_end { ACTION }** + +This is based on kdebug.probe_end function. + +## Tracing built-in variable + +**argevent** +event object, you can print it by: print(argevent), it will print events +into human readable string, the result is mostly same as each entry of +/sys/kernel/debug/tracing/trace + +**argname** +event name, each event have a name associated with it. + +**arg1..9** +get argument 1..9 of event object. + + +## Timer syntax + +**tick-Ns { ACTION }** +**tick-Nsec { ACTION }** +**tick-Nms { ACTION }** +**tick-Nmsec { ACTION }** +**tick-Nus { ACTION }** +**tick-Nusec { ACTION }** + +**profile-Ns { ACTION }** +**profile-Nsec { ACTION }** +**profile-Nms { ACTION }** +**profile-Nmsec { ACTION }** +**profile-Nus { ACTION }** +**profile-Nusec { ACTION }** + +architecture overview picture reference(pnp format) +one-liners +simple event tracing + +# Advanced tracing pattern + +Aggregation/Histogram +thread local +flame graph + +# Overhead/Performance + +ktap have more fast boot time thant Systemtap(try the helloword script) +ktap have little memory usage than Systemtap +and some scripts show that ktap have a little overhead then Systemtap +(we choosed two scripts to compare, function profile, stack profile. +this is not means all scripts in Systemtap have big overhead than ktap) + + +# FAQ + +**Q: Why use bytecode design?** +A: Using bytecode would be a clean and lightweight solution, + you don't need gcc toolchain to compile every scripts, all you + need is a ktapvm kernel modules and userspace tool called ktap. + Since its language virtual machine design, it have great portability, + suppose you are working at a multi-arch cluster, if you want to run + a tracing script on each board, you won't need cross-compile tracing + script onto all board, what you really need to do is use ktap tool + to run script just in time. + + Bytecode based design also will make executing more safer, than native code + generation. + + Reality already showing that SystemTap is not widely used in embedded Linux, + caused by problem of SystemTap's architecture design choice, it's a natural + design for Redhat and IBM, because Redhat/IBM is focusing on server area, + not embedded area. + +**Q: What's the differences with SystemTap and Dtrace?** +A: For SystemTap, the answer is already mentioned at above question, + SystemTap use translator design, for trade-off on performance with usability, + based on GCC, that's what ktap want to solve. + + For Dtrace, one common design with Dtrace is also use bytecode, so basically + Dtrace and ktap is on the same road. There have some projects aim to porting + Dtrace from Solaris to Linux, but the process is still on the road, Dtrace + is rooted in Solaris, and there have many huge differences between Solaris + tracing infrastructure with Linux's. + + Dtrace is based on D language, a language subset of C, it's a restricted + language, like without for-looping, for safty use in production system. + It seems that Dtrace for Linux only support x86 architecture, not work on + powerpc and arm/mips, obviously it's not suit for embedded Linux currently. + + Dtrace use ctf as input for debuginfo handing, compare with vmlinux for + SystemTap. + + On the license part, Dtrace is released as CDDL, which is incompatible with + GPL(this is why it's impossible to upstream Dtrace into mainline). + +**Q: Why use dynamically typed language? but not statically typed language?** +A: It's hard to say which one is more better than other, dynamically typed + language bring efficiency and fast prototype production, but loosing type + check at compiling phase, and easy to make mistake in runtime, also it's + need many runtime checking, In contrast, statically typed language win on + programing safety, and performance. Statically language would suit for + interoperate with kernel, as kernel is wrote mainly in C, Need to note that + SystemTap and Dtrace both is statically language. + + ktap choose dynamically typed language as initial implementation. + +**Q: Why we need ktap for event tracing? There already have a built-in ftrace** +A: This also is a common question for all dynamic tracing tool, not only ktap. + ktap provide more flexibility than built-in tracing infrastructure. Suppose + you need print a global variable when tracepoint hit, or you want print + backtrace, even more, you want to store some info into associative array, and + display it in histogram style when tracing end, in these case, some of them + ftrace can take it, some of them ftrace can not. + Overall, ktap provide you with great flexibility to scripting your own trace + need. + +**Q: How about the performance? Is ktap slow?** +A: ktap is not slow, the bytecode is very high-level, based on lua, the language + virtual machine is register-based(compare with stack-based), with little + instruction, the table data structure is heavily optimized in ktapvm. + ktap use per-cpu allocation in many place, without global locking scheme, + it's very fast when executing tracepoint callback. + Performance benchmark showing that the overhead of ktap running is nearly + 10%(store event name into associative array), compare with full speed + running without any tracepoint enabled. + + ktap will optimize overhead all the time, hopefully the overhead will + decrease to little than 5%, even more. + +**Q: Why not porting a high level language implementation into kernel directly? + Like python/JVM?** +A: I take serious on the size of vm and memory footprint. Python vm is large, + it's not suit to embed into kernel, and python have some functionality + which we don't need. + + The bytecode of other high level language is also big, ktap only have 32 + bytecodes, python/java/erlang have nearly two hundred bytecodes. + There also have some problems when porting those language into kernel, + userspace programming have many differences with kernel programming, + like float numbers, handle sleeping code carefully in kernel, deadloop is + not allowed in kernel, multi-thread management, etc.., so it's impossible + to porting language implementation into kernel with little adaption work. + +**Q: What's the status of ktap now?** +A: Basically it works on x86-32, x86-64, powerpc, arm, it also could work for + other hardware architecture, but not proven yet(I don't have enough hardware + to test) + If you found some bug, fix it on you own programming skill, or report to me. + +**Q: How to hack ktap? I want to write some extensions onto ktap.** +A: welcome hacking. + You can write your own library to fulfill your specific need, + you can write any script as you want. + +**Q: What's the plan of ktap? any roadmap?** +A: the current plan is deliver stable ktapvm kernel modules, more ktap script, + and bugfix. + + +# References + +* [Linux Performance Analysis and Tools][LPAT] +* [Dtrace Blog][dtraceblog] +* [Dtrace User Guide][dug] +* [LWN: ktap -- yet another kernel tracer][lwn] +* [ktap introduction in LinuxCon Japan 2013][lcj] + +[LPAT]: http://www.brendangregg.com/Slides/SCaLE_Linux_Performance2013.pdf +[dtraceblog]: http://dtrace.org/blogs/ +[dug]: http://docs.huihoo.com/opensolaris/dtrace-user-guide/html/index.html +[lwn]: http://lwn.net/Articles/551314/ +[lcj]: http://events.linuxfoundation.org/sites/events/files/lcjpcojp13_zhangwei.pdf + + +# History + +* ktap was invented at 2002 +* First RFC sent to LKML at 2012.12.31 +* The code was released in github at 2013.01.18 +* ktap released v0.1 at 2013.05.21 +* ktap released v0.2 at 2013.07.31 + +For more release info, please look at RELEASES.txt in project root directory. + +# Sample scripts + +1. simplest one-liner command to enable all tracepoints + + ktap -e "trace *:* { print(argevent) }" + +2. syscall tracing on target process + + ktap -e "trace syscalls:* { print(argevent) }" -- ls + +3. function tracing + + ktap -e "trace ftrace:function { print(argevent) }" + + ktap -e "trace ftrace:function /ip==mutex*/ { print(argevent) }" + +4. simple syscall tracing + + trace syscalls:* { + print(cpu(), pid(), execname(), argevent) + } + +5. syscall tracing in histogram style + + s = {} + + trace syscalls:sys_enter_* { + s[argname] += 1 + } + + trace_end { + histogram(s) + } + +6. kprobe tracing + + trace probe:do_sys_open dfd=%di fname=%dx flags=%cx mode=+4($stack) { + print("entry:", execname(), argevent) + } + + trace probe:do_sys_open%return fd=$retval { + print("exit:", execname(), argevent) + } + +7. uprobe tracing + + trace probe:/lib/libc.so.6:0x000773c0 { + print("entry:", execname(), argevent) + } + + trace probe:/lib/libc.so.6:0x000773c0%return { + print("exit:", execname(), argevent) + } + +8. timer + + tick-1ms { + printf("time fired on one cpu\n"); + } + + profile-2s { + printf("time fired on every cpu\n"); + } + +More sample scripts can be found at scripts/ directory. + + +# Appendix + +Here is the complete syntax of ktap in extended BNF. +(based on lua syntax: http://www.lua.org/manual/5.1/manual.html#5.1) + + chunk ::= {stat [';']} [laststat [';'] + + block ::= chunk + + stat ::= varlist '=' explist | + functioncall | + { block } | + while exp { block } | + repeat block until exp | + if exp { block {elseif exp { block }} [else block] } | + for Name '=' exp ',' exp [',' exp] { block } | + for namelist in explist { block } | + function funcname funcbody | + local function Name funcbody | + local namelist ['=' explist] + + laststat ::= return [explist] | break + + funcname ::= Name {'.' Name} [':' Name] + + varlist ::= var {',' var} + + var ::= Name | prefixexp '[' exp ']'| prefixexp '.' Name + + namelist ::= Name {',' Name} + + explist ::= {exp ',' exp + + exp ::= nil | false | true | Number | String | '...' | function | + prefixexp | tableconstructor | exp binop exp | unop exp + + prefixexp ::= var | functioncall | '(' exp ')' + + functioncall ::= prefixexp args | prefixexp ':' Name args + + args ::= '(' [explist] ')' | tableconstructor | String + + function ::= function funcbody + + funcbody ::= '(' [parlist] ')' { block } + + parlist ::= namelist [',' '...'] | '...' + + tableconstructor ::= '{' [fieldlist] '}' + + fieldlist ::= field {fieldsep field} [fieldsep] + + field ::= '[' exp ']' '=' exp | Name '=' exp | exp + + fieldsep ::= ',' | ';' + + binop ::= '+' | '-' | '*' | '/' | '^' | '%' | '..' | + '<' | '<=' | '>' | '>=' | '==' | '!=' | + and | or + + unop ::= '-' + diff --git a/drivers/staging/ktap/include/ktap.h b/drivers/staging/ktap/include/ktap.h new file mode 100644 index 000000000000..076dd4aa6477 --- /dev/null +++ b/drivers/staging/ktap/include/ktap.h @@ -0,0 +1,169 @@ +#ifndef __KTAP_H__ +#define __KTAP_H__ + +#include "ktap_types.h" +#include "ktap_opcodes.h" + +#include <linux/version.h> +#include <linux/hardirq.h> +#include <linux/perf_event.h> +#include <linux/trace_seq.h> + +typedef struct ktap_Reg { + const char *name; + ktap_cfunction func; +} ktap_Reg; + +struct ktap_probe_event { + struct list_head list; + struct perf_event *perf; + ktap_state *ks; + ktap_closure *cl; +}; + +/* this structure allocate on stack */ +struct ktap_event { + struct ktap_probe_event *pevent; + struct ftrace_event_call *call; + struct trace_entry *entry; + int entry_size; + struct pt_regs *regs; +}; + +enum { + KTAP_PERCPU_DATA_STATE, + KTAP_PERCPU_DATA_STACK, + KTAP_PERCPU_DATA_BUFFER, + KTAP_PERCPU_DATA_BUFFER2, + KTAP_PERCPU_DATA_BTRACE, + + KTAP_PERCPU_DATA_MAX +}; + +#define KTAP_PERCPU_BUFFER_SIZE (3 * PAGE_SIZE) + +int gettimeofday_us(void); +ktap_state *kp_newstate(struct ktap_parm *parm, struct dentry *dir); +void kp_exit(ktap_state *ks); +void kp_final_exit(ktap_state *ks); +ktap_state *kp_newthread(ktap_state *mainthread); +void kp_exitthread(ktap_state *ks); +ktap_closure *kp_load(ktap_state *ks, unsigned char *buff); +void kp_call(ktap_state *ks, StkId func, int nresults); +void kp_optimize_code(ktap_state *ks, int level, ktap_proto *f); +void kp_register_lib(ktap_state *ks, const char *libname, const ktap_Reg *funcs); +void *kp_percpu_data(int type); + +void kp_init_baselib(ktap_state *ks); +void kp_init_oslib(ktap_state *ks); +void kp_init_kdebuglib(ktap_state *ks); +void kp_init_timerlib(ktap_state *ks); +void kp_init_ansilib(ktap_state *ks); + +int kp_probe_init(ktap_state *ks); +void kp_probe_exit(ktap_state *ks); + +void kp_perf_event_register(ktap_state *ks, struct perf_event_attr *attr, + struct task_struct *task, char *filter, + ktap_closure *cl); + +void kp_event_getarg(ktap_state *ks, ktap_value *ra, int n); +void kp_event_tostring(ktap_state *ks, struct trace_seq *seq); + +int kp_strfmt(ktap_state *ks, struct trace_seq *seq); + +void kp_transport_write(ktap_state *ks, const void *data, size_t length); +void kp_transport_event_write(ktap_state *ks, struct ktap_event *e); +void kp_transport_print_backtrace(ktap_state *ks); +void *kp_transport_reserve(ktap_state *ks, size_t length); +void kp_transport_exit(ktap_state *ks); +int kp_transport_init(ktap_state *ks, struct dentry *dir); + +void kp_exit_timers(ktap_state *ks); + +extern int kp_max_exec_count; + +/* get from kernel/trace/trace.h */ +static __always_inline int trace_get_context_bit(void) +{ + int bit; + + if (in_interrupt()) { + if (in_nmi()) + bit = 0; + else if (in_irq()) + bit = 1; + else + bit = 2; + } else + bit = 3; + + return bit; +} + +/* use a special timer context kp_state instead use this recursion approach? */ +DECLARE_PER_CPU(int, kp_recursion_context[PERF_NR_CONTEXTS]); + +static __always_inline int get_recursion_context(void) +{ + int rctx = trace_get_context_bit(); + + if (__this_cpu_read(kp_recursion_context[rctx])) + return -1; + + __this_cpu_write(kp_recursion_context[rctx], true); + barrier(); + + return rctx; +} + +static inline void put_recursion_context(int rctx) +{ + barrier(); + __this_cpu_write(kp_recursion_context[rctx], false); +} + + +extern unsigned int kp_stub_exit_instr; + +static inline void set_next_as_exit(ktap_state *ks) +{ + ktap_callinfo *ci; + + ci = ks->ci; + if (!ci) + return; + + ci->u.l.savedpc = &kp_stub_exit_instr; + + /* See precall, ci changed to ci->prev after invoke C function */ + if (ci->prev) { + ci = ci->prev; + ci->u.l.savedpc = &kp_stub_exit_instr; + } +} + +#define kp_verbose_printf(ks, ...) \ + if (G(ks)->parm->verbose) \ + kp_printf(ks, "[verbose] "__VA_ARGS__); + +/* get argument operation macro */ +#define kp_arg(ks, n) ((ks)->ci->func + (n)) +#define kp_arg_nr(ks) ((int)(ks->top - (ks->ci->func + 1))) + +#define kp_arg_check(ks, narg, type) \ + do { \ + if (unlikely(ttypenv(kp_arg(ks, narg)) != type)) { \ + kp_error(ks, "wrong type of argument %d\n", narg);\ + return -1; \ + } \ + } while (0) + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 5, 0) +#define SPRINT_SYMBOL sprint_symbol_no_offset +#else +#define SPRINT_SYMBOL sprint_symbol +#endif + +#endif /* __KTAP_H__ */ diff --git a/drivers/staging/ktap/include/ktap_opcodes.h b/drivers/staging/ktap/include/ktap_opcodes.h new file mode 100644 index 000000000000..31c558b680f4 --- /dev/null +++ b/drivers/staging/ktap/include/ktap_opcodes.h @@ -0,0 +1,240 @@ +#ifndef __KTAP_BYTECODE_H__ +#define __KTAP_BYTECODE_H__ + + +/* opcode is copied from lua initially */ + +typedef enum { +/*---------------------------------------------------------------------- + * name args description + * ------------------------------------------------------------------------*/ +OP_MOVE,/* A B R(A) := R(B) */ +OP_LOADK,/* A Bx R(A) := Kst(Bx) */ +OP_LOADKX,/* A R(A) := Kst(extra arg) */ +OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ +OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */ +OP_GETUPVAL,/* A B R(A) := UpValue[B] */ + +OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */ +OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ + +OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */ +OP_SETTABUP_INCR,/* A B C UpValue[A][RK(B)] += RK(C) */ +OP_SETUPVAL,/* A B UpValue[B] := R(A) */ +OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ +OP_SETTABLE_INCR,/* A B C R(A)[RK(B)] += RK(C) */ + +OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */ + +OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ + +OP_ADD,/* A B C R(A) := RK(B) + RK(C) */ +OP_SUB,/* A B C R(A) := RK(B) - RK(C) */ +OP_MUL,/* A B C R(A) := RK(B) * RK(C) */ +OP_DIV,/* A B C R(A) := RK(B) / RK(C) */ +OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ +OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ +OP_UNM,/* A B R(A) := -R(B) */ +OP_NOT,/* A B R(A) := not R(B) */ +OP_LEN,/* A B R(A) := length of R(B) */ + +OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ + +OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */ +OP_EQ,/* A B C if ((RK(B) == RK(C)) != A) then pc++ */ +OP_LT,/* A B C if ((RK(B) < RK(C)) != A) then pc++ */ +OP_LE,/* A B C if ((RK(B) <= RK(C)) != A) then pc++ */ + +OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ + +OP_FORLOOP,/* A sBx R(A)+=R(A+2); + if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ +OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */ + +OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ +OP_TFORLOOP,/* A sBx if R(A+1) != nil then { R(A)=R(A+1); pc += sBx }*/ + +OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ + +OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ + +OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */ + +OP_EXTRAARG,/* Ax extra (larger) argument for previous opcode */ + +OP_EVENT,/* A B C R(A) := R(B)[C] */ + +OP_EVENTNAME, /* A R(A) = event_name() */ + +OP_EVENTARG,/* A B R(A) := event_arg(B)*/ + +OP_LOAD_GLOBAL,/* A B C R(A) := R(B)[C] */ + +OP_EXIT, + +} OpCode; + + +#define NUM_OPCODES ((int)OP_LOAD_GLOBAL + 1) + + +enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ + + +/* + * ** size and position of opcode arguments. + * */ +#define SIZE_C 9 +#define SIZE_B 9 +#define SIZE_Bx (SIZE_C + SIZE_B) +#define SIZE_A 8 +#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) + +#define SIZE_OP 6 + +#define POS_OP 0 +#define POS_A (POS_OP + SIZE_OP) +#define POS_C (POS_A + SIZE_A) +#define POS_B (POS_C + SIZE_C) +#define POS_Bx POS_C +#define POS_Ax POS_A + + + +/* + * ** limits for opcode arguments. + * ** we use (signed) int to manipulate most arguments, + * ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) + * */ +#define MAXARG_Bx ((1<<SIZE_Bx)-1) +#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */ + +#define MAXARG_Ax ((1<<SIZE_Ax)-1) + +#define MAXARG_A ((1<<SIZE_A)-1) +#define MAXARG_B ((1<<SIZE_B)-1) +#define MAXARG_C ((1<<SIZE_C)-1) + + +/* creates a mask with `n' 1 bits at position `p' */ +#define MASK1(n,p) ((~((~(ktap_instruction)0)<<(n)))<<(p)) + +/* creates a mask with `n' 0 bits at position `p' */ +#define MASK0(n,p) (~MASK1(n,p)) + +/* + * ** the following macros help to manipulate instructions + * */ + +#define GET_OPCODE(i) ((OpCode)((i)>>POS_OP) & MASK1(SIZE_OP,0)) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((((ktap_instruction)o)<<POS_OP)&MASK1(SIZE_OP,POS_OP)))) + +#define getarg(i,pos,size) ((int)((i)>>pos) & MASK1(size,0)) +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ + ((((ktap_instruction)v)<<pos)&MASK1(size,pos)))) + +#define GETARG_A(i) getarg(i, POS_A, SIZE_A) +#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A) + +#define GETARG_A(i) getarg(i, POS_A, SIZE_A) +#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A) + +#define GETARG_B(i) getarg(i, POS_B, SIZE_B) +#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B) + +#define GETARG_C(i) getarg(i, POS_C, SIZE_C) +#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C) + +#define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx) +#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx) + +#define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax) +#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax) + +#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx) +#define SETARG_sBx(i,b) SETARG_Bx((i), (unsigned int)(b)+MAXARG_sBx) + +#define CREATE_ABC(o,a,b,c) (((ktap_instruction)(o))<<POS_OP) \ + | (((ktap_instruction)(a))<<POS_A) \ + | (((ktap_instruction)(b))<<POS_B) \ + | (((ktap_instruction)(c))<<POS_C) + +#define CREATE_ABx(o,a,bc) (((ktap_instruction)(o))<<POS_OP) \ + | (((ktap_instruction)(a))<<POS_A) \ + | (((ktap_instruction)(bc))<<POS_Bx) + +#define CREATE_Ax(o,a) (((ktap_instruction)(o))<<POS_OP) \ + | (((ktap_instruction)(a))<<POS_Ax) + + + +/* + * ** Macros to operate RK indices + * */ + +/* this bit 1 means constant (0 means register) */ +#define BITRK (1 << (SIZE_B - 1)) + +/* test whether value is a constant */ +#define ISK(x) ((x) & BITRK) + +/* gets the index of the constant */ +#define INDEXK(r) ((int)(r) & ~BITRK) + +#define MAXINDEXRK (BITRK - 1) + +/* code a constant index as a RK value */ +#define RKASK(x) ((x) | BITRK) + + +/* + * ** invalid register that fits in 8 bits + * */ +#define NO_REG MAXARG_A + + +/* + * ** R(x) - register + * ** Kst(x) - constant (in constant table) + * ** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) + * */ + + + +/* + * ** masks for instruction properties. The format is: + * ** bits 0-1: op mode + * ** bits 2-3: C arg mode + * ** bits 4-5: B arg mode + * ** bit 6: instruction set register A + * ** bit 7: operator is a test (next instruction must be a jump) + * */ + +enum OpArgMask { + OpArgN, /* argument is not used */ + OpArgU, /* argument is used */ + OpArgR, /* argument is a register or a jump offset */ + OpArgK /* argument is a constant or register/constant */ +}; + +extern const u8 ktap_opmodes[NUM_OPCODES]; + +#define getOpMode(m) ((enum OpMode)ktap_opmodes[m] & 3) +#define getBMode(m) ((enum OpArgMask)(ktap_opmodes[m] >> 4) & 3) +#define getCMode(m) ((enum OpArgMask)(ktap_opmodes[m] >> 2) & 3) +#define testAMode(m) (ktap_opmodes[m] & (1 << 6)) +#define testTMode(m) (ktap_opmodes[m] & (1 << 7)) + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + +extern const char *const ktap_opnames[NUM_OPCODES + 1]; + +#endif /* __KTAP_BYTECODE_H__ */ diff --git a/drivers/staging/ktap/include/ktap_types.h b/drivers/staging/ktap/include/ktap_types.h new file mode 100644 index 000000000000..cf1cef41b584 --- /dev/null +++ b/drivers/staging/ktap/include/ktap_types.h @@ -0,0 +1,674 @@ +#ifndef __KTAP_TYPES_H__ +#define __KTAP_TYPES_H__ + +/* opcode is copied from lua initially */ + +#ifdef __KERNEL__ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/semaphore.h> +#include <linux/wait.h> +#else +typedef char u8; +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#endif + +typedef struct ktap_parm { + char *trunk; /* __user */ + int trunk_len; + int argc; + char **argv; /* __user */ + int verbose; + int trace_pid; + int workload; + int trace_cpu; + int print_timestamp; +} ktap_parm; + +/* + * Ioctls that can be done on a ktap fd: + * todo: use _IO macro in include/uapi/asm-generic/ioctl.h + */ +#define KTAP_CMD_IOC_VERSION ('$' + 0) +#define KTAP_CMD_IOC_RUN ('$' + 1) +#define KTAP_CMD_IOC_EXIT ('$' + 3) + +#define KTAP_ENV "_ENV" + +#define KTAP_VERSION_MAJOR "0" +#define KTAP_VERSION_MINOR "2" + +#define KTAP_VERSION "ktap " KTAP_VERSION_MAJOR "." KTAP_VERSION_MINOR +#define KTAP_AUTHOR "Jovi Zhangwei <jovi.zhangwei@gmail.com>" +#define KTAP_COPYRIGHT KTAP_VERSION " Copyright (C) 2012-2013, " KTAP_AUTHOR + +#define MYINT(s) (s[0] - '0') +#define VERSION (MYINT(KTAP_VERSION_MAJOR) * 16 + MYINT(KTAP_VERSION_MINOR)) +#define FORMAT 0 /* this is the official format */ + +#define KTAP_SIGNATURE "\033ktap" + +/* data to catch conversion errors */ +#define KTAPC_TAIL "\x19\x93\r\n\x1a\n" + +/* size in bytes of header of binary files */ +#define KTAPC_HEADERSIZE (sizeof(KTAP_SIGNATURE) - sizeof(char) + 2 + \ + 6 + sizeof(KTAPC_TAIL) - sizeof(char)) + +typedef int ktap_instruction; + +typedef union ktap_gcobject ktap_gcobject; + +#define CommonHeader ktap_gcobject *next; u8 tt; + +struct ktap_state; +typedef int (*ktap_cfunction) (struct ktap_state *ks); + +typedef union ktap_string { + int dummy; /* ensures maximum alignment for strings */ + struct { + CommonHeader; + u8 extra; /* reserved words for short strings; "has hash" for longs */ + unsigned int hash; + size_t len; /* number of characters in string */ + } tsv; +} ktap_string; + +#define getstr(ts) (const char *)((ts) + 1) +#define eqshrstr(a,b) ((a) == (b)) + +#define svalue(o) getstr(rawtsvalue(o)) + + +union _ktap_value { + ktap_gcobject *gc; /* collectable objects */ + void *p; /* light userdata */ + int b; /* booleans */ + ktap_cfunction f; /* light C functions */ + long n; /* numbers */ +}; + + +typedef struct ktap_value { + union _ktap_value val; + int type; +} ktap_value; + +typedef ktap_value * StkId; + + + +typedef union ktap_udata { + struct { + CommonHeader; + size_t len; /* number of bytes */ + } uv; +} ktap_udata; + +/* + * Description of an upvalue for function prototypes + */ +typedef struct ktap_upvaldesc { + ktap_string *name; /* upvalue name (for debug information) */ + u8 instack; /* whether it is in stack */ + u8 idx; /* index of upvalue (in stack or in outer function's list) */ +} ktap_upvaldesc; + +/* + * Description of a local variable for function prototypes + * (used for debug information) + */ +typedef struct ktap_locvar { + ktap_string *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} ktap_locvar; + + +typedef struct ktap_upval { + CommonHeader; + ktap_value *v; /* points to stack or to its own value */ + union { + ktap_value value; /* the value (when closed) */ + struct { /* double linked list (when open) */ + struct ktap_upval *prev; + struct ktap_upval *next; + } l; + } u; +} ktap_upval; + + +#define KTAP_STACK_MAX_ENTRIES 10 + +typedef struct ktap_btrace { + CommonHeader; + unsigned int nr_entries; + unsigned long entries[KTAP_STACK_MAX_ENTRIES]; +} ktap_btrace; + +#define ktap_closure_header \ + CommonHeader; u8 nupvalues; ktap_gcobject *gclist + +typedef struct ktap_cclosure { + ktap_closure_header; + ktap_cfunction f; + ktap_value upvalue[1]; /* list of upvalues */ +} ktap_cclosure; + + +typedef struct ktap_lclosure { + ktap_closure_header; + struct ktap_proto *p; + struct ktap_upval *upvals[1]; /* list of upvalues */ +} ktap_lclosure; + + +typedef struct ktap_closure { + struct ktap_cclosure c; + struct ktap_lclosure l; +} ktap_closure; + + +typedef struct ktap_proto { + CommonHeader; + ktap_value *k; /* constants used by the function */ + ktap_instruction *code; + struct ktap_proto **p; /* functions defined inside the function */ + int *lineinfo; /* map from opcodes to source lines (debug information) */ + struct ktap_locvar *locvars; /* information about local variables (debug information) */ + struct ktap_upvaldesc *upvalues; /* upvalue information */ + ktap_closure *cache; /* last created closure with this prototype */ + ktap_string *source; /* used for debug information */ + int sizeupvalues; /* size of 'upvalues' */ + int sizek; /* size of `k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of `p' */ + int sizelocvars; + int linedefined; + int lastlinedefined; + u8 numparams; /* number of fixed parameters */ + u8 is_vararg; + u8 maxstacksize; /* maximum stack used by this function */ +} ktap_proto; + + +/* + * information about a call + */ +typedef struct ktap_callinfo { + StkId func; /* function index in the stack */ + StkId top; /* top for this function */ + struct ktap_callinfo *prev, *next; /* dynamic call link */ + short nresults; /* expected number of results from this function */ + u8 callstatus; + int extra; + union { + struct { /* only for Lua functions */ + StkId base; /* base for this function */ + const unsigned int *savedpc; + } l; + struct { /* only for C functions */ + int ctx; /* context info. in case of yields */ + u8 status; + } c; + } u; +} ktap_callinfo; + + +/* + * ktap_tables + */ +typedef union ktap_tkey { + struct { + union _ktap_value value_; + int tt_; + struct ktap_tnode *next; /* for chaining */ + } nk; + ktap_value tvk; +} ktap_tkey; + + +typedef struct ktap_tnode { + ktap_value i_val; + ktap_tkey i_key; +} ktap_tnode; + + +typedef struct ktap_table { + CommonHeader; +#ifdef __KERNEL__ + arch_spinlock_t lock; +#endif + u8 flags; /* 1<<p means tagmethod(p) is not present */ + u8 lsizenode; /* log2 of size of `node' array */ + int sizearray; /* size of `array' array */ + ktap_value *array; /* array part */ + ktap_tnode *node; + ktap_tnode *lastfree; /* any free position is before this position */ + ktap_gcobject *gclist; +} ktap_table; + +#define lmod(s,size) ((int)((s) & ((size)-1))) + +enum AGGREGATION_TYPE { + AGGREGATION_TYPE_COUNT, + AGGREGATION_TYPE_MAX, + AGGREGATION_TYPE_MIN, + AGGREGATION_TYPE_SUM, + AGGREGATION_TYPE_AVG +}; + +typedef struct ktap_aggrtable { + CommonHeader; + ktap_table **pcpu_tbl; + ktap_gcobject *gclist; +} ktap_aggrtable; + +typedef struct ktap_aggraccval { + CommonHeader; + int type; + int val; + int more; +} ktap_aggraccval; + +typedef struct ktap_stringtable { + ktap_gcobject **hash; + int nuse; + int size; +} ktap_stringtable; + +typedef struct ktap_global_state { + ktap_stringtable strt; /* hash table for strings */ + ktap_value registry; + unsigned int seed; /* randonized seed for hashes */ + u8 gcstate; /* state of garbage collector */ + u8 gckind; /* kind of GC running */ + u8 gcrunning; /* true if GC is running */ + + ktap_gcobject *allgc; /* list of all collectable objects */ + + ktap_upval uvhead; /* head of double-linked list of all open upvalues */ + + struct ktap_state *mainthread; +#ifdef __KERNEL__ + ktap_parm *parm; + pid_t trace_pid; + struct task_struct *trace_task; + cpumask_var_t cpumask; + struct ring_buffer *buffer; + struct dentry *trace_pipe_dentry; + int nr_builtin_cfunction; + ktap_value *cfunction_tbl; + struct task_struct *task; + int trace_enabled; + struct list_head timers; + struct list_head probe_events_head; + int exit; + int wait_user; + ktap_closure *trace_end_closure; +#endif + int error; +} ktap_global_state; + +typedef struct ktap_state { + CommonHeader; + u8 status; + ktap_global_state *g; + int stop; + StkId top; + ktap_callinfo *ci; + const unsigned long *oldpc; + StkId stack_last; + StkId stack; + int stacksize; + ktap_gcobject *openupval; + ktap_callinfo baseci; + + int debug; + int version; + int gcrunning; + + /* list of temp collectable objects, free when thread exit */ + ktap_gcobject *gclist; + +#ifdef __KERNEL__ + struct ktap_event *current_event; + int aggr_accval; /* for temp value storage */ +#endif +} ktap_state; + + +typedef struct gcheader { + CommonHeader; +} gcheader; + +/* + * Union of all collectable objects + */ +union ktap_gcobject { + gcheader gch; /* common header */ + union ktap_string ts; + union ktap_udata u; + struct ktap_closure cl; + struct ktap_table h; + struct ktap_aggrtable ah; + struct ktap_aggraccval acc; + struct ktap_proto p; + struct ktap_upval uv; + struct ktap_state th; /* thread */ + struct ktap_btrace bt; /* thread */ +}; + +#define gch(o) (&(o)->gch) +/* macros to convert a GCObject into a specific value */ +#define rawgco2ts(o) (&((o)->ts)) +#define gco2ts(o) (&rawgco2ts(o)->tsv) + +#define gco2uv(o) (&((o)->uv)) + +#define obj2gco(v) ((ktap_gcobject *)(v)) + + +#ifdef __KERNEL__ +#define ktap_assert(s) +#else +#define ktap_assert(s) +#if 0 +#define ktap_assert(s) \ + do { \ + if (!s) { \ + printf("assert failed %s, %d\n", __func__, __LINE__);\ + exit(0); \ + } \ + } while(0) +#endif +#endif + +#define check_exp(c,e) (e) + + +typedef int ktap_number; + + +#define ktap_number2int(i,n) ((i)=(int)(n)) + + +/* predefined values in the registry */ +#define KTAP_RIDX_MAINTHREAD 1 +#define KTAP_RIDX_GLOBALS 2 +#define KTAP_RIDX_LAST KTAP_RIDX_GLOBALS + + +#define KTAP_TNONE (-1) + +#define KTAP_TNIL 0 +#define KTAP_TBOOLEAN 1 +#define KTAP_TLIGHTUSERDATA 2 +#define KTAP_TNUMBER 3 +#define KTAP_TSTRING 4 +#define KTAP_TSHRSTR (KTAP_TSTRING | (0 << 4)) /* short strings */ +#define KTAP_TLNGSTR (KTAP_TSTRING | (1 << 4)) /* long strings */ +#define KTAP_TTABLE 5 +#define KTAP_TFUNCTION 6 +#define KTAP_TLCL (KTAP_TFUNCTION | (0 << 4)) /* closure */ +#define KTAP_TLCF (KTAP_TFUNCTION | (1 << 4)) /* light C function */ +#define KTAP_TCCL (KTAP_TFUNCTION | (2 << 4)) /* C closure */ +#define KTAP_TUSERDATA 7 +#define KTAP_TTHREAD 8 + +#define KTAP_NUMTAGS 9 + +#define KTAP_TPROTO 11 +#define KTAP_TUPVAL 12 + +#define KTAP_TEVENT 13 + +#define KTAP_TBTRACE 14 + +#define KTAP_TAGGRTABLE 15 +#define KTAP_TAGGRACCVAL 16 +#define KTAP_TAGGRVAL 17 + +#define ttype(o) ((o->type) & 0x3F) +#define settype(obj, t) ((obj)->type = (t)) + + + +/* raw type tag of a TValue */ +#define rttype(o) ((o)->type) + +/* tag with no variants (bits 0-3) */ +#define novariant(x) ((x) & 0x0F) + +/* type tag of a TValue with no variants (bits 0-3) */ +#define ttypenv(o) (novariant(rttype(o))) + +#define val_(o) ((o)->val) + +#define bvalue(o) (val_(o).b) +#define nvalue(o) (val_(o).n) +#define hvalue(o) (&val_(o).gc->h) +#define ahvalue(o) (&val_(o).gc->ah) +#define aggraccvalue(o) (&val_(o).gc->acc) +#define CLVALUE(o) (&val_(o).gc->cl.l) +#define clcvalue(o) (&val_(o).gc->cl.c) +#define clvalue(o) (&val_(o).gc->cl) +#define rawtsvalue(o) (&val_(o).gc->ts) +#define pvalue(o) (&val_(o).p) +#define fvalue(o) (val_(o).f) +#define rawuvalue(o) (&val_(o).gc->u) +#define uvalue(o) (&rawuvalue(o)->uv) +#define evalue(o) (val_(o).p) +#define btvalue(o) (&val_(o).gc->bt) + +#define gcvalue(o) (val_(o).gc) + +#define isnil(o) (o->type == KTAP_TNIL) +#define isboolean(o) (o->type == KTAP_TBOOLEAN) +#define isfalse(o) (isnil(o) || (isboolean(o) && bvalue(o) == 0)) + +#define ttisshrstring(o) ((o)->type == KTAP_TSHRSTR) +#define ttisstring(o) (((o)->type & 0x0F) == KTAP_TSTRING) +#define ttisnumber(o) ((o)->type == KTAP_TNUMBER) +#define ttisfunc(o) ((o)->type == KTAP_TFUNCTION) +#define ttistable(o) ((o)->type == KTAP_TTABLE) +#define ttisaggrtable(o) ((o)->type == KTAP_TAGGRTABLE) +#define ttisaggrval(o) ((o)->type == KTAP_TAGGRVAL) +#define ttisaggracc(o) ((o)->type == KTAP_TAGGRACCVAL) +#define ttisnil(o) ((o)->type == KTAP_TNIL) +#define ttisboolean(o) ((o)->type == KTAP_TBOOLEAN) +#define ttisequal(o1,o2) ((o1)->type == (o2)->type) +#define ttisevent(o) ((o)->type == KTAP_TEVENT) +#define ttisbtrace(o) ((o)->type == KTAP_TBTRACE) + +#define ttisclone(o) ttisbtrace(o) + + +#define setnilvalue(obj) \ + { ktap_value *io = (obj); io->val.n = 0; settype(io, KTAP_TNIL); } + +#define setbvalue(obj, x) \ + { ktap_value *io = (obj); io->val.b = (x); settype(io, KTAP_TBOOLEAN); } + +#define setnvalue(obj, x) \ + { ktap_value *io = (obj); io->val.n = (x); settype(io, KTAP_TNUMBER); } + +#define setaggrvalue(obj, x) \ + { ktap_value *io = (obj); io->val.n = (x); settype(io, KTAP_TAGGRVAL); } + +#define setaggraccvalue(obj,x) \ + { ktap_value *io=(obj); \ + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TAGGRACCVAL); } + +#define setsvalue(obj, x) \ + { ktap_value *io = (obj); \ + ktap_string *x_ = (x); \ + io->val.gc = (ktap_gcobject *)x_; settype(io, x_->tsv.tt); } + +#define setcllvalue(obj, x) \ + { ktap_value *io = (obj); \ + io->val.gc = (ktap_gcobject *)x; settype(io, KTAP_TLCL); } + +#define sethvalue(obj,x) \ + { ktap_value *io=(obj); \ + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TTABLE); } + +#define setahvalue(obj,x) \ + { ktap_value *io=(obj); \ + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TAGGRTABLE); } + +#define setfvalue(obj,x) \ + { ktap_value *io=(obj); val_(io).f=(x); settype(io, KTAP_TLCF); } + +#define setthvalue(L,obj,x) \ + { ktap_value *io=(obj); \ + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TTHREAD); } + +#define setevalue(obj, x) \ + { ktap_value *io=(obj); val_(io).p = (x); settype(io, KTAP_TEVENT); } + +#define setbtvalue(obj,x) \ + { ktap_value *io=(obj); \ + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TBTRACE); } + +#define setobj(obj1,obj2) \ + { const ktap_value *io2=(obj2); ktap_value *io1=(obj1); \ + io1->val = io2->val; io1->type = io2->type; } + +#define rawequalobj(t1, t2) \ + (ttisequal(t1, t2) && kp_equalobjv(NULL, t1, t2)) + +#define equalobj(ks, t1, t2) rawequalobj(t1, t2) + +#define incr_top(ks) {ks->top++;} + +#define NUMADD(a, b) ((a) + (b)) +#define NUMSUB(a, b) ((a) - (b)) +#define NUMMUL(a, b) ((a) * (b)) +#define NUMDIV(a, b) ((a) / (b)) +#define NUMUNM(a) (-(a)) +#define NUMEQ(a, b) ((a) == (b)) +#define NUMLT(a, b) ((a) < (b)) +#define NUMLE(a, b) ((a) <= (b)) +#define NUMISNAN(a) (!NUMEQ((a), (a))) + +/* todo: floor and pow in kernel */ +#define NUMMOD(a, b) ((a) % (b)) +#define NUMPOW(a, b) (pow(a, b)) + + +ktap_string *kp_tstring_newlstr(ktap_state *ks, const char *str, size_t l); +ktap_string *kp_tstring_newlstr_local(ktap_state *ks, const char *str, size_t l); +ktap_string *kp_tstring_new(ktap_state *ks, const char *str); +ktap_string *kp_tstring_new_local(ktap_state *ks, const char *str); +int kp_tstring_eqstr(ktap_string *a, ktap_string *b); +unsigned int kp_string_hash(const char *str, size_t l, unsigned int seed); +int kp_tstring_eqlngstr(ktap_string *a, ktap_string *b); +int kp_tstring_cmp(const ktap_string *ls, const ktap_string *rs); +void kp_tstring_resize(ktap_state *ks, int newsize); +void kp_tstring_freeall(ktap_state *ks); + +ktap_value *kp_table_set(ktap_state *ks, ktap_table *t, const ktap_value *key); +ktap_table *kp_table_new(ktap_state *ks); +const ktap_value *kp_table_getint(ktap_table *t, int key); +void kp_table_setint(ktap_state *ks, ktap_table *t, int key, ktap_value *v); +const ktap_value *kp_table_get(ktap_table *t, const ktap_value *key); +void kp_table_setvalue(ktap_state *ks, ktap_table *t, const ktap_value *key, ktap_value *val); +void kp_table_resize(ktap_state *ks, ktap_table *t, int nasize, int nhsize); +void kp_table_resizearray(ktap_state *ks, ktap_table *t, int nasize); +void kp_table_free(ktap_state *ks, ktap_table *t); +int kp_table_length(ktap_state *ks, ktap_table *t); +void kp_table_dump(ktap_state *ks, ktap_table *t); +void kp_table_clear(ktap_state *ks, ktap_table *t); +void kp_table_histogram(ktap_state *ks, ktap_table *t); +int kp_table_next(ktap_state *ks, ktap_table *t, StkId key); +void kp_table_atomic_inc(ktap_state *ks, ktap_table *t, ktap_value *key, int n); +void kp_aggraccval_dump(ktap_state *ks, ktap_aggraccval *acc); +ktap_aggrtable *kp_aggrtable_new(ktap_state *ks); +ktap_table *kp_aggrtable_synthesis(ktap_state *ks, ktap_aggrtable *ah); +void kp_aggrtable_dump(ktap_state *ks, ktap_aggrtable *ah); +void kp_aggrtable_free(ktap_state *ks, ktap_aggrtable *ah); +void kp_aggrtable_set(ktap_state *ks, ktap_aggrtable *ah, + ktap_value *key, ktap_value *val); +void kp_aggrtable_get(ktap_state *ks, ktap_aggrtable *ah, + ktap_value *key, ktap_value *val); +void kp_aggrtable_histogram(ktap_state *ks, ktap_aggrtable *ah); +void kp_obj_dump(ktap_state *ks, const ktap_value *v); +void kp_showobj(ktap_state *ks, const ktap_value *v); +int kp_objlen(ktap_state *ks, const ktap_value *rb); +void kp_objclone(ktap_state *ks, const ktap_value *o, ktap_value *newo, + ktap_gcobject **list); +ktap_gcobject *kp_newobject(ktap_state *ks, int type, size_t size, ktap_gcobject **list); +int kp_equalobjv(ktap_state *ks, const ktap_value *t1, const ktap_value *t2); +ktap_closure *kp_newlclosure(ktap_state *ks, int n); +ktap_proto *kp_newproto(ktap_state *ks); +ktap_upval *kp_newupval(ktap_state *ks); +void kp_free_gclist(ktap_state *ks, ktap_gcobject *o); +void kp_free_all_gcobject(ktap_state *ks); +void kp_header(u8 *h); + +int kp_str2d(const char *s, size_t len, ktap_number *result); + +#define kp_realloc(ks, v, osize, nsize, t) \ + ((v) = (t *)kp_reallocv(ks, v, osize * sizeof(t), nsize * sizeof(t))) + +#define kp_error(ks, args...) \ + do { \ + kp_printf(ks, "error: "args); \ + G(ks)->error = 1; \ + kp_exit(ks); \ + } while(0) + +#ifdef __KERNEL__ +#define G(ks) (ks->g) + +void *kp_malloc(ktap_state *ks, int size); +void kp_free(ktap_state *ks, void *addr); +void *kp_reallocv(ktap_state *ks, void *addr, int oldsize, int newsize); +void *kp_zalloc(ktap_state *ks, int size); + +void kp_printf(ktap_state *ks, const char *fmt, ...); +extern void __kp_puts(ktap_state *ks, const char *str); +extern void __kp_bputs(ktap_state *ks, const char *str); + +#define kp_puts(ks, str) ({ \ + static const char *trace_printk_fmt \ + __attribute__((section("__trace_printk_fmt"))) = \ + __builtin_constant_p(str) ? str : NULL; \ + \ + if (__builtin_constant_p(str)) \ + __kp_bputs(ks, trace_printk_fmt); \ + else \ + __kp_puts(ks, str); \ +}) + +#else +/* + * this is used for ktapc tstring operation, tstring need G(ks)->strt + * and G(ks)->seed, so ktapc need to init those field + */ +#define G(ks) (&dummy_global_state) +extern ktap_global_state dummy_global_state; + +#define kp_malloc(ks, size) malloc(size) +#define kp_free(ks, block) free(block) +#define kp_reallocv(ks, block, osize, nsize) realloc(block, nsize) +#define kp_printf(ks, args...) printf(args) +#define kp_puts(ks, str) printf("%s", str) +#define kp_exit(ks) exit(EXIT_FAILURE) +#endif + +#define __maybe_unused __attribute__((unused)) + +/* + * KTAP_QL describes how error messages quote program elements. + * CHANGE it if you want a different appearance. + */ +#define KTAP_QL(x) "'" x "'" +#define KTAP_QS KTAP_QL("%s") + +#endif /* __KTAP_TYPES_H__ */ + diff --git a/drivers/staging/ktap/interpreter/ktap.c b/drivers/staging/ktap/interpreter/ktap.c new file mode 100644 index 000000000000..18d8fc8ec63d --- /dev/null +++ b/drivers/staging/ktap/interpreter/ktap.c @@ -0,0 +1,235 @@ +/* + * ktap.c - ktapvm kernel module main entry + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * this file is the first file to be compile, add CONFIG_ checking in here. + * See Requirements in doc/introduction.txt + */ + +#include <linux/version.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) +#error "Currently ktap don't support kernel older than 3.1" +#endif + +#if !CONFIG_EVENT_TRACING +#error "Please enable CONFIG_EVENT_TRACING before compile ktap" +#endif + +#if !CONFIG_PERF_EVENTS +#error "Please enable CONFIG_PERF_EVENTS before compile ktap" +#endif + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/file.h> +#include <linux/fcntl.h> +#include <linux/sched.h> +#include <linux/poll.h> +#include <linux/anon_inodes.h> +#include <linux/debugfs.h> +#include <linux/vmalloc.h> +#include "../include/ktap.h" + +static int load_trunk(struct ktap_parm *parm, unsigned long **buff) +{ + int ret; + unsigned long *vmstart; + + vmstart = vmalloc(parm->trunk_len); + if (!vmstart) + return -ENOMEM; + + ret = copy_from_user(vmstart, (void __user *)parm->trunk, + parm->trunk_len); + if (ret < 0) { + vfree(vmstart); + return -EFAULT; + } + + *buff = vmstart; + return 0; +} + +int gettimeofday_us(void) +{ + struct timeval tv; + + do_gettimeofday(&tv); + return tv.tv_sec * USEC_PER_SEC + tv.tv_usec; +} + +struct dentry *kp_dir_dentry; +static atomic_t kp_is_running = ATOMIC_INIT(0); + +/* Ktap Main Entry */ +static int ktap_main(struct file *file, ktap_parm *parm) +{ + unsigned long *buff = NULL; + ktap_state *ks; + ktap_closure *cl; + int start_time, delta_time; + int ret; + + if (atomic_inc_return(&kp_is_running) != 1) { + atomic_dec(&kp_is_running); + pr_info("only one ktap thread allow to run\n"); + return -EBUSY; + } + + start_time = gettimeofday_us(); + + ks = kp_newstate(parm, kp_dir_dentry); + if (unlikely(!ks)) { + ret = -ENOEXEC; + goto out; + } + + file->private_data = ks; + + ret = load_trunk(parm, &buff); + if (ret) { + pr_err("cannot load file\n"); + goto out; + } + + cl = kp_load(ks, (unsigned char *)buff); + + vfree(buff); + + if (cl) { + /* optimize bytecode before excuting */ + kp_optimize_code(ks, 0, cl->l.p); + + delta_time = gettimeofday_us() - start_time; + kp_verbose_printf(ks, "booting time: %d (us)\n", delta_time); + kp_call(ks, ks->top - 1, 0); + } + + kp_final_exit(ks); + + out: + atomic_dec(&kp_is_running); + return ret; +} + + +static void print_version(void) +{ +} + +static long ktap_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + ktap_parm parm; + int ret; + + switch (cmd) { + case KTAP_CMD_IOC_VERSION: + print_version(); + return 0; + case KTAP_CMD_IOC_RUN: + ret = copy_from_user(&parm, (void __user *)arg, + sizeof(ktap_parm)); + if (ret < 0) + return -EFAULT; + + return ktap_main(file, &parm); + default: + return -EINVAL; + }; + + return 0; +} + +static const struct file_operations ktap_fops = { + .llseek = no_llseek, + .unlocked_ioctl = ktap_ioctl, +}; + +static long ktapvm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int new_fd, err; + struct file *new_file; + + new_fd = get_unused_fd(); + if (new_fd < 0) + return new_fd; + + new_file = anon_inode_getfile("[ktap]", &ktap_fops, NULL, O_RDWR); + if (IS_ERR(new_file)) { + err = PTR_ERR(new_file); + put_unused_fd(new_fd); + return err; + } + + file->private_data = NULL; + fd_install(new_fd, new_file); + return new_fd; +} + +static const struct file_operations ktapvm_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = ktapvm_ioctl, +}; + +unsigned int kp_stub_exit_instr; + +static int __init init_ktap(void) +{ + struct dentry *ktapvm_dentry; + + kp_dir_dentry = debugfs_create_dir("ktap", NULL); + if (!kp_dir_dentry) { + pr_err("ktap: debugfs_create_dir failed\n"); + return -1; + } + + ktapvm_dentry = debugfs_create_file("ktapvm", 0444, kp_dir_dentry, NULL, + &ktapvm_fops); + + if (!ktapvm_dentry) { + pr_err("ktapvm: cannot create ktapvm file\n"); + debugfs_remove_recursive(kp_dir_dentry); + return -1; + } + + SET_OPCODE(kp_stub_exit_instr, OP_EXIT); + + return 0; +} + +static void __exit exit_ktap(void) +{ + debugfs_remove_recursive(kp_dir_dentry); +} + +module_init(init_ktap); +module_exit(exit_ktap); + +MODULE_AUTHOR("Jovi Zhangwei <jovi.zhangwei@gmail.com>"); +MODULE_DESCRIPTION("ktap"); +MODULE_LICENSE("GPL"); + +int kp_max_exec_count = 10000; +module_param_named(max_exec_count, kp_max_exec_count, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_exec_count, "non-mainthread max instruction execution count"); + diff --git a/drivers/staging/ktap/interpreter/library/ansilib.c b/drivers/staging/ktap/interpreter/library/ansilib.c new file mode 100644 index 000000000000..d058373e5f30 --- /dev/null +++ b/drivers/staging/ktap/interpreter/library/ansilib.c @@ -0,0 +1,153 @@ +/* + * ansilib.c - ANSI escape sequences library + * + * http://en.wikipedia.org/wiki/ANSI_escape_code + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "../../include/ktap.h" + +/** + * function ansi.clear_screen - Move cursor to top left and clear screen. + * + * Description: Sends ansi code for moving cursor to top left and then the + * ansi code for clearing the screen from the cursor position to the end. + */ + +static int ktap_lib_clear_screen(ktap_state *ks) +{ + kp_printf(ks, "\033[1;1H\033[J"); + return 0; +} + +/** + * function ansi.set_color - Set the ansi Select Graphic Rendition mode. + * @fg: Foreground color to set. + * + * Description: Sends ansi code for Select Graphic Rendition mode for the + * given forground color. Black (30), Blue (34), Green (32), Cyan (36), + * Red (31), Purple (35), Brown (33), Light Gray (37). + */ + +static int ktap_lib_set_color(ktap_state *ks) +{ + int fg; + + kp_arg_check(ks, 1, KTAP_TNUMBER); + + fg = nvalue(kp_arg(ks, 1)); + kp_printf(ks, "\033[%dm", fg); + return 0; +} + +/** + * function ansi.set_color2 - Set the ansi Select Graphic Rendition mode. + * @fg: Foreground color to set. + * @bg: Background color to set. + * + * Description: Sends ansi code for Select Graphic Rendition mode for the + * given forground color, Black (30), Blue (34), Green (32), Cyan (36), + * Red (31), Purple (35), Brown (33), Light Gray (37) and the given + * background color, Black (40), Red (41), Green (42), Yellow (43), + * Blue (44), Magenta (45), Cyan (46), White (47). + */ +static int ktap_lib_set_color2(ktap_state *ks) +{ + int fg, bg; + + kp_arg_check(ks, 1, KTAP_TNUMBER); + kp_arg_check(ks, 2, KTAP_TNUMBER); + + fg = nvalue(kp_arg(ks, 1)); + bg = nvalue(kp_arg(ks, 2)); + kp_printf(ks, "\033[%d;%dm", fg, bg); + return 0; +} + +/** + * function ansi.set_color3 - Set the ansi Select Graphic Rendition mode. + * @fg: Foreground color to set. + * @bg: Background color to set. + * @attr: Color attribute to set. + * + * Description: Sends ansi code for Select Graphic Rendition mode for the + * given forground color, Black (30), Blue (34), Green (32), Cyan (36), + * Red (31), Purple (35), Brown (33), Light Gray (37), the given + * background color, Black (40), Red (41), Green (42), Yellow (43), + * Blue (44), Magenta (45), Cyan (46), White (47) and the color attribute + * All attributes off (0), Intensity Bold (1), Underline Single (4), + * Blink Slow (5), Blink Rapid (6), Image Negative (7). + */ +static int ktap_lib_set_color3(ktap_state *ks) +{ + int fg, bg, attr; + + kp_arg_check(ks, 1, KTAP_TNUMBER); + kp_arg_check(ks, 2, KTAP_TNUMBER); + kp_arg_check(ks, 3, KTAP_TNUMBER); + + fg = nvalue(kp_arg(ks, 1)); + bg = nvalue(kp_arg(ks, 2)); + attr = nvalue(kp_arg(ks, 3)); + + if (attr) + kp_printf(ks, "\033[%d;%d;%dm", fg, bg, attr); + else + kp_printf(ks, "\033[%d;%dm", fg, bg); + + return 0; +} + +/** + * function ansi.reset_color - Resets Select Graphic Rendition mode. + * + * Description: Sends ansi code to reset foreground, background and color + * attribute to default values. + */ +static int ktap_lib_reset_color(ktap_state *ks) +{ + kp_printf(ks, "\033[0;0m"); + return 0; +} + +/** + * function ansi.new_line - Move cursor to new line. + * + * Description: Sends ansi code new line. + */ +static int ktap_lib_new_line (ktap_state *ks) +{ + kp_printf(ks, "\12"); + return 0; +} + +static const ktap_Reg ansi_funcs[] = { + {"clear_screen", ktap_lib_clear_screen}, + {"set_color", ktap_lib_set_color}, + {"set_color2", ktap_lib_set_color2}, + {"set_color3", ktap_lib_set_color3}, + {"reset_color", ktap_lib_reset_color}, + {"new_line", ktap_lib_new_line}, + {NULL} +}; + +void kp_init_ansilib(ktap_state *ks) +{ + kp_register_lib(ks, "ansi", ansi_funcs); +} diff --git a/drivers/staging/ktap/interpreter/library/baselib.c b/drivers/staging/ktap/interpreter/library/baselib.c new file mode 100644 index 000000000000..4bcdc620f9d9 --- /dev/null +++ b/drivers/staging/ktap/interpreter/library/baselib.c @@ -0,0 +1,455 @@ +/* + * baselib.c - ktapvm kernel module base library + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/hardirq.h> +#include <linux/kallsyms.h> +#include <linux/sched.h> +#include <linux/uaccess.h> +#include <linux/utsname.h> +#include <linux/time.h> +#include <linux/clocksource.h> +#include <linux/ring_buffer.h> +#include <linux/stacktrace.h> +#include "../../include/ktap.h" + +static int ktap_lib_next(ktap_state *ks) +{ + ktap_table *t = hvalue(ks->top - 2); + + if (kp_table_next(ks, t, ks->top-1)) { + ks->top += 1; + return 2; + } else { + ks->top -= 1; + setnilvalue(ks->top++); + return 1; + } +} + +static int ktap_lib_pairs(ktap_state *ks) +{ + ktap_value *v = kp_arg(ks, 1); + ktap_table *t; + + if (G(ks)->mainthread != ks) { + kp_error(ks, "only mainthread can call table pairs\n"); + return -1; + } + + if (ttistable(v)) { + t = hvalue(v); + } else if (ttisaggrtable(v)) { + t = kp_aggrtable_synthesis(ks, ahvalue(v)); + } else if (isnil(v)) { + kp_error(ks, "table is nil in pairs\n"); + return 0; + } else { + kp_error(ks, "wrong argument for pairs\n"); + return 0; + } + + setfvalue(ks->top++, ktap_lib_next); + sethvalue(ks->top++, t); + setnilvalue(ks->top++); + return 3; +} + +static int ktap_lib_len(ktap_state *ks) +{ + int len = kp_objlen(ks, kp_arg(ks, 1)); + + if (len < 0) + return -1; + + setnvalue(ks->top, len); + incr_top(ks); + return 1; +} + +static int ktap_lib_print(ktap_state *ks) +{ + int i; + int n = kp_arg_nr(ks); + + for (i = 1; i <= n; i++) { + ktap_value *arg = kp_arg(ks, i); + if (i > 1) + kp_puts(ks, "\t"); + kp_showobj(ks, arg); + } + + kp_puts(ks, "\n"); + + return 0; +} + +/* don't engage with tstring when printf, use buffer directly */ +static int ktap_lib_printf(ktap_state *ks) +{ + struct trace_seq *seq; + + preempt_disable_notrace(); + + seq = kp_percpu_data(KTAP_PERCPU_DATA_BUFFER); + trace_seq_init(seq); + + if (kp_strfmt(ks, seq)) + return 0; + + seq->buffer[seq->len] = '\0'; + kp_transport_write(ks, seq->buffer, seq->len + 1); + + preempt_enable_notrace(); + return 0; +} + +#ifdef CONFIG_STACKTRACE +static int ktap_lib_print_backtrace(ktap_state *ks) +{ + kp_transport_print_backtrace(ks); + return 0; +} +#else +static int ktap_lib_print_backtrace(ktap_state *ks) +{ + kp_error(ks, "Please enable CONFIG_STACKTRACE before use " + "ktap print_backtrace\n"); + return 0; +} +#endif + +static int ktap_lib_backtrace(ktap_state *ks) +{ + struct stack_trace trace; + ktap_btrace *bt; + + bt = kp_percpu_data(KTAP_PERCPU_DATA_BTRACE); + + trace.nr_entries = 0; + trace.skip = 10; + trace.max_entries = KTAP_STACK_MAX_ENTRIES; + trace.entries = &bt->entries[0]; + save_stack_trace(&trace); + + bt->nr_entries = trace.nr_entries; + setbtvalue(ks->top, bt); + incr_top(ks); + return 1; +} + +extern unsigned long long ns2usecs(cycle_t nsec); +static int ktap_lib_print_trace_clock(ktap_state *ks) +{ + unsigned long long t; + unsigned long secs, usec_rem; + u64 timestamp; + + /* use ring buffer's timestamp */ + timestamp = ring_buffer_time_stamp(G(ks)->buffer, smp_processor_id()); + + t = ns2usecs(timestamp); + usec_rem = do_div(t, USEC_PER_SEC); + secs = (unsigned long)t; + + kp_printf(ks, "%5lu.%06lu\n", secs, usec_rem); + + return 0; +} + +static int ktap_lib_exit(ktap_state *ks) +{ + kp_exit(ks); + + /* do not execute bytecode any more in this thread */ + return -1; +} + +static int ktap_lib_pid(ktap_state *ks) +{ + pid_t pid = task_tgid_vnr(current); + + setnvalue(ks->top, (int)pid); + incr_top(ks); + return 1; +} + +static int ktap_lib_tid(ktap_state *ks) +{ + pid_t pid = task_pid_vnr(current); + + setnvalue(ks->top, (int)pid); + incr_top(ks); + return 1; +} + +static int ktap_lib_execname(ktap_state *ks) +{ + ktap_string *ts = kp_tstring_new(ks, current->comm); + setsvalue(ks->top, ts); + incr_top(ks); + return 1; +} + +static int ktap_lib_cpu(ktap_state *ks) +{ + setnvalue(ks->top, smp_processor_id()); + incr_top(ks); + return 1; +} + +static int ktap_lib_num_cpus(ktap_state *ks) +{ + setnvalue(ks->top, num_online_cpus()); + incr_top(ks); + return 1; +} + +static int ktap_lib_in_interrupt(ktap_state *ks) +{ + int ret = in_interrupt(); + + setnvalue(ks->top, ret); + incr_top(ks); + return 1; +} + +static int ktap_lib_arch(ktap_state *ks) +{ + setsvalue(ks->top, kp_tstring_new(ks, utsname()->machine)); + incr_top(ks); + return 1; +} + +static int ktap_lib_kernel_v(ktap_state *ks) +{ + setsvalue(ks->top, kp_tstring_new(ks, utsname()->release)); + incr_top(ks); + return 1; +} + +static int ktap_lib_user_string(ktap_state *ks) +{ + unsigned long addr; + char str[256] = {0}; + int ret; + + kp_arg_check(ks, 1, KTAP_TNUMBER); + + addr = nvalue(kp_arg(ks, 1)); + + pagefault_disable(); + ret = __copy_from_user_inatomic((void *)str, (const void *)addr, 256); + (void) &ret; /* Silence compiler warning. */ + pagefault_enable(); + str[255] = '\0'; + setsvalue(ks->top, kp_tstring_new(ks, str)); + + incr_top(ks); + return 1; +} + +static int ktap_lib_histogram(ktap_state *ks) +{ + ktap_value *v = kp_arg(ks, 1); + + if (G(ks)->mainthread != ks) { + kp_error(ks, "only mainthread can call table historgram\n"); + return -1; + } + + if (ttistable(v)) + kp_table_histogram(ks, hvalue(v)); + else if (ttisaggrtable(v)) + kp_aggrtable_histogram(ks, ahvalue(v)); + + return 0; +} + +static int ktap_lib_aggr_table(ktap_state *ks) +{ + ktap_aggrtable *ah; + + ah = kp_aggrtable_new(ks); + setahvalue(ks->top, ah); + incr_top(ks); + return 1; +} + +static int ktap_lib_aggr_count(ktap_state *ks) +{ + setaggrvalue(ks->top, AGGREGATION_TYPE_COUNT); + incr_top(ks); + return 1; +} + +static int ktap_lib_aggr_max(ktap_state *ks) +{ + kp_arg_check(ks, 1, KTAP_TNUMBER); + + ks->aggr_accval = nvalue(kp_arg(ks, 1)); + setaggrvalue(ks->top, AGGREGATION_TYPE_MAX); + incr_top(ks); + return 1; +} + +static int ktap_lib_aggr_min(ktap_state *ks) +{ + kp_arg_check(ks, 1, KTAP_TNUMBER); + + ks->aggr_accval = nvalue(kp_arg(ks, 1)); + setaggrvalue(ks->top, AGGREGATION_TYPE_MIN); + incr_top(ks); + return 1; +} + +static int ktap_lib_aggr_sum(ktap_state *ks) +{ + kp_arg_check(ks, 1, KTAP_TNUMBER); + + ks->aggr_accval = nvalue(kp_arg(ks, 1)); + setaggrvalue(ks->top, AGGREGATION_TYPE_SUM); + incr_top(ks); + return 1; +} + +static int ktap_lib_aggr_avg(ktap_state *ks) +{ + kp_arg_check(ks, 1, KTAP_TNUMBER); + + ks->aggr_accval = nvalue(kp_arg(ks, 1)); + setaggrvalue(ks->top, AGGREGATION_TYPE_AVG); + incr_top(ks); + return 1; +} + +static int ktap_lib_delete(ktap_state *ks) +{ + kp_arg_check(ks, 1, KTAP_TTABLE); + + kp_table_clear(ks, hvalue(kp_arg(ks, 1))); + return 0; +} + +static int ktap_lib_gettimeofday_us(ktap_state *ks) +{ + setnvalue(ks->top, gettimeofday_us()); + incr_top(ks); + + return 1; +} + +/* + * use gdb to get field offset of struct task_struct, for example: + * + * gdb vmlinux + * (gdb)p &(((struct task_struct *)0).prio) + */ +static int ktap_lib_curr_task_info(ktap_state *ks) +{ + int offset; + int fetch_bytes; + + kp_arg_check(ks, 1, KTAP_TNUMBER); + + offset = nvalue(kp_arg(ks, 1)); + + if (kp_arg_nr(ks) == 1) + fetch_bytes = 4; /* default fetch 4 bytes*/ + else { + kp_arg_check(ks, 2, KTAP_TNUMBER); + fetch_bytes = nvalue(kp_arg(ks, 2)); + } + + if (offset >= sizeof(struct task_struct)) { + setnilvalue(ks->top++); + kp_error(ks, "access out of bound value of task_struct\n"); + return 1; + } + +#define RET_VALUE ((unsigned long)current + offset) + + switch (fetch_bytes) { + case 4: + setnvalue(ks->top, *(unsigned int *)RET_VALUE); + break; + case 8: + setnvalue(ks->top, *(unsigned long *)RET_VALUE); + break; + default: + kp_error(ks, "unsupported fetch bytes in curr_task_info\n"); + setnilvalue(ks->top); + break; + } + +#undef RET_VALUE + + incr_top(ks); + return 1; +} + +/* + * This built-in function mainly purpose scripts/schedule/schedtimes.kp + */ +static int ktap_lib_in_iowait(ktap_state *ks) +{ + setnvalue(ks->top, current->in_iowait); + incr_top(ks); + + return 1; +} + +static const ktap_Reg base_funcs[] = { + {"pairs", ktap_lib_pairs}, + {"len", ktap_lib_len}, + {"print", ktap_lib_print}, + {"printf", ktap_lib_printf}, + {"print_backtrace", ktap_lib_print_backtrace}, + {"backtrace", ktap_lib_backtrace}, + {"print_trace_clock", ktap_lib_print_trace_clock}, + {"in_interrupt", ktap_lib_in_interrupt}, + {"exit", ktap_lib_exit}, + {"pid", ktap_lib_pid}, + {"tid", ktap_lib_tid}, + {"execname", ktap_lib_execname}, + {"cpu", ktap_lib_cpu}, + {"num_cpus", ktap_lib_num_cpus}, + {"arch", ktap_lib_arch}, + {"kernel_v", ktap_lib_kernel_v}, + {"user_string", ktap_lib_user_string}, + {"histogram", ktap_lib_histogram}, + {"aggr_table", ktap_lib_aggr_table}, + {"count", ktap_lib_aggr_count}, + {"max", ktap_lib_aggr_max}, + {"min", ktap_lib_aggr_min}, + {"sum", ktap_lib_aggr_sum}, + {"avg", ktap_lib_aggr_avg}, + + {"delete", ktap_lib_delete}, + {"gettimeofday_us", ktap_lib_gettimeofday_us}, + {"curr_taskinfo", ktap_lib_curr_task_info}, + {"in_iowait", ktap_lib_in_iowait}, + {NULL} +}; + +void kp_init_baselib(ktap_state *ks) +{ + kp_register_lib(ks, NULL, base_funcs); +} diff --git a/drivers/staging/ktap/interpreter/library/kdebug.c b/drivers/staging/ktap/interpreter/library/kdebug.c new file mode 100644 index 000000000000..a9477beeaebf --- /dev/null +++ b/drivers/staging/ktap/interpreter/library/kdebug.c @@ -0,0 +1,449 @@ +/* + * kdebug.c - ktap probing core implementation + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/module.h> +#include <linux/ctype.h> +#include <linux/version.h> +#include <linux/ftrace_event.h> +#include "../../include/ktap.h" + +static void ktap_call_probe_closure(ktap_state *mainthread, ktap_closure *cl, + struct ktap_event *e) +{ + ktap_state *ks; + ktap_value *func; + + ks = kp_newthread(mainthread); + setcllvalue(ks->top, cl); + func = ks->top; + incr_top(ks); + + ks->current_event = e; + + kp_call(ks, func, 0); + + ks->current_event = NULL; + kp_exitthread(ks); +} + +void kp_event_tostring(ktap_state *ks, struct trace_seq *seq) +{ + struct ktap_event *e = ks->current_event; + struct trace_iterator *iter; + struct trace_event *ev; + enum print_line_t ret = TRACE_TYPE_NO_CONSUME; + + /* Simulate the iterator */ + + /* + * use temp percpu buffer as trace_iterator + * we cannot use same temp buffer as printf. + */ + iter = kp_percpu_data(KTAP_PERCPU_DATA_BUFFER2); + + trace_seq_init(&iter->seq); + iter->ent = e->entry; + + ev = &(e->call->event); + if (ev) + ret = ev->funcs->trace(iter, 0, ev); + + if (ret != TRACE_TYPE_NO_CONSUME) { + struct trace_seq *s = &iter->seq; + int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; + + s->buffer[len] = '\0'; + trace_seq_puts(seq, s->buffer); + } +} + +#if 0 +/* check pt_regs defintion in linux/arch/x86/include/asm/ptrace.h */ +/* support other architecture pt_regs showing */ +static void event_regstr(ktap_state *ks, struct ktap_event *e, StkId ra) +{ + struct pt_regs *regs = e->regs; + char str[256] = {0}; + +#if defined(CONFIG_X86_32) + snprintf(str, sizeof(str), + "{ax: 0x%lx, orig_ax: 0x%lx, bx: 0x%lx, cx: 0x%lx, dx: 0x%lx, " + "si: 0x%lx, di: 0x%lx, bp: 0x%lx, ds: 0x%lx, es: 0x%lx, fs: 0x%lx, " + "gs: 0x%lx, ip: 0x%lx, cs: 0x%lx, flags: 0x%lx, sp: 0x%lx, ss: 0x%lx}\n", + regs->ax, regs->orig_ax, regs->bx, regs->cx, regs->dx, + regs->si, regs->di, regs->bp, regs->ds, regs->es, regs->fs, + regs->gs, regs->ip, regs->cs, regs->flags, regs->sp, regs->ss); +#elif defined(CONFIG_X86_64) + /* x86_64 pt_regs doesn't have ds, es, fs or gs. */ + snprintf(str, sizeof(str), + "{ax: 0x%lx, orig_ax: 0x%lx, bx: 0x%lx, cx: 0x%lx, dx: 0x%lx, " + "si: 0x%lx, di: 0x%lx, r8: 0x%lx, r9: 0x%lx, r10: 0x%lx, r11: 0x%lx, " + "r12: 0x%lx, r13: 0x%lx, r14: 0x%lx, r15: 0x%lx, bp: 0x%lx, ip: 0x%lx, " + "cs: 0x%lx, flags: 0x%lx, sp: 0x%lx, ss: 0x%lx}\n", + regs->ax, regs->orig_ax, regs->bx, regs->cx, regs->dx, + regs->si, regs->di, regs->r8, regs->r9, regs->r10, regs->r11, + regs->r12, regs->r13, regs->r14, regs->r15, regs->bp, regs->ip, + regs->cs, regs->flags, regs->sp, regs->ss); +#endif + setsvalue(ra, kp_tstring_new_local(ks, str)); +} +#endif + +/***************************/ +/* This definition should keep update with kernel/trace/trace.h */ +struct ftrace_event_field { + struct list_head link; + const char *name; + const char *type; + int filter_type; + int offset; + int size; + int is_signed; +}; + +static struct list_head *ktap_get_fields(struct ftrace_event_call *event_call) +{ + if (!event_call->class->get_fields) + return &event_call->class->fields; + return event_call->class->get_fields(event_call); +} + +static void get_field_value(ktap_state *ks, struct ktap_event *e, + struct ftrace_event_field *field, ktap_value *ra) +{ + void *value = (unsigned char *)e->entry + field->offset; + + if (field->size == 4) { + int n = *(int *)value; + setnvalue(ra, n); + return; + } else if (field->size == 8) { + long n = *(long *)value; + setnvalue(ra, n); + return; + } + + if (!strncmp(field->type, "char", 4)) { + setsvalue(ra, kp_tstring_new(ks, (char *)value)); + return; + } +} + +void kp_event_getarg(ktap_state *ks, ktap_value *ra, int n) +{ + struct ktap_event *e = ks->current_event; + int index = n; + struct ftrace_event_field *field; + struct list_head *head; + + /* this is very slow and not safe, fix it in future */ + head = ktap_get_fields(e->call); + list_for_each_entry_reverse(field, head, link) { + if (--index == 0) { + get_field_value(ks, e, field, ra); + return; + } + } + + setnilvalue(ra); + return; +} + +/* Callback function for perf event subsystem + * make ktap reentrant, don't disable irq in callback function, + * same as perf and ftrace. to make reentrant, we need some + * percpu data to be context isolation(irq/sirq/nmi/process) + * + * perf callback already consider on the recursion issue, + * so ktap don't need to check again in here. + * + * Note tracepoint handler is calling with rcu_read_lock. + */ +static void ktap_overflow_callback(struct perf_event *event, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + struct ktap_probe_event *ktap_pevent; + struct ktap_event e; + ktap_state *ks; + int rctx; + + ktap_pevent = event->overflow_handler_context; + ks = ktap_pevent->ks; + + if (unlikely(ks->stop)) + return; + + rctx = get_recursion_context(); + if (rctx < 0) + return; + + /* profile perf event don't have valid associated tp_event */ + if (event->tp_event) { + e.call = event->tp_event; + e.entry = data->raw->data; + e.entry_size = data->raw->size; + } + e.pevent = ktap_pevent; + e.regs = regs; + + ktap_call_probe_closure(ks, ktap_pevent->cl, &e); + + put_recursion_context(rctx); +} + +static void perf_destructor(struct ktap_probe_event *ktap_pevent) +{ + perf_event_release_kernel(ktap_pevent->perf); +} + +static int (*kp_ftrace_profile_set_filter)(struct perf_event *event, + int event_id, char *filter_str); + +/* + * Generic perf event register function + * used by tracepoints/kprobe/uprobe/profile-timer/hw_breakpoint. + */ +void kp_perf_event_register(ktap_state *ks, struct perf_event_attr *attr, + struct task_struct *task, char *filter, + ktap_closure *cl) +{ + struct ktap_probe_event *ktap_pevent; + struct perf_event *event; + int cpu, ret; + + kp_verbose_printf(ks, "enable perf event id: %d, filter: %s " + "pid: %d\n", attr->config, filter, + task ? task_tgid_vnr(task) : -1); + + /* + * don't tracing until ktap_wait, the reason is: + * 1). some event may hit before apply filter + * 2). more simple to manage tracing thread + * 3). avoid race with mainthread. + * + * Another way to do this is make attr.disabled as 1, then use + * perf_event_enable after filter apply, however, perf_event_enable + * was not exported in kernel older than 3.3, so we drop this method. + */ + ks->stop = 1; + + for_each_cpu(cpu, G(ks)->cpumask) { + ktap_pevent = kp_zalloc(ks, sizeof(*ktap_pevent)); + ktap_pevent->ks = ks; + ktap_pevent->cl = cl; + event = perf_event_create_kernel_counter(attr, cpu, task, + ktap_overflow_callback, + ktap_pevent); + if (IS_ERR(event)) { + int err = PTR_ERR(event); + kp_error(ks, "unable register perf event %d on cpu %d, " + "err: %d\n", attr->config, cpu, err); + kp_free(ks, ktap_pevent); + return; + } + + ktap_pevent->perf = event; + INIT_LIST_HEAD(&ktap_pevent->list); + list_add_tail(&ktap_pevent->list, &G(ks)->probe_events_head); + + if (!filter) + continue; + + ret = kp_ftrace_profile_set_filter(event, attr->config, filter); + if (ret) { + kp_error(ks, "unable set filter %s for event id %d, " + "ret: %d\n", filter, attr->config, ret); + perf_destructor(ktap_pevent); + list_del(&ktap_pevent->list); + kp_free(ks, ktap_pevent); + return; + } + } +} + +static void end_probes(struct ktap_state *ks) +{ + struct ktap_probe_event *ktap_pevent; + struct list_head *tmp, *pos; + struct list_head *head = &G(ks)->probe_events_head; + + list_for_each(pos, head) { + ktap_pevent = container_of(pos, struct ktap_probe_event, + list); + perf_destructor(ktap_pevent); + } + /* + * Ensure our callback won't be called anymore. The buffers + * will be freed after that. + */ + tracepoint_synchronize_unregister(); + + list_for_each_safe(pos, tmp, head) { + ktap_pevent = container_of(pos, struct ktap_probe_event, + list); + list_del(&ktap_pevent->list); + kp_free(ks, ktap_pevent); + } +} + +static int ktap_lib_probe_by_id(ktap_state *ks) +{ + const char *ids_str; + char *start; + ktap_closure *cl; + struct task_struct *task = G(ks)->trace_task; + char filter_str[128] = {0}; + char *filter, *ptr1, *sep, *ptr; + + kp_arg_check(ks, 1, KTAP_TSTRING); + kp_arg_check(ks, 2, KTAP_TFUNCTION); + + ids_str = svalue(kp_arg(ks, 1)); + cl = clvalue(kp_arg(ks, 2)); + + start = (char *)ids_str; + + again: + filter = NULL; + + sep = strchr(start, ','); + if (!sep) + ptr1 = strchr(start, '/'); + else + ptr1 = strnchr(start, sep - start, '/'); + + if (ptr1) { + char *ptr2 = strrchr(ptr1 + 1, '/'); + + if (ptr2) { + memset(filter_str, 0, sizeof(filter_str)); + strncpy(filter_str, ptr1 + 1, ptr2 - ptr1 - 1); + filter = &filter_str[0]; + } else { + kp_printf(ks, "cannot parse ids_str: %s\n", ids_str); + return -1; + } + } + + for (ptr = start; *ptr != ',' && *ptr != '\0' && *ptr != '/'; ptr++) { + char token[32] = {0}; + int id; + int i = 0; + + if (*ptr == ' ') + continue; + + while (isdigit(*ptr)) { + token[i++] = *ptr++; + } + + if (!kstrtoint(token, 10, &id)) { + struct perf_event_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.type = PERF_TYPE_TRACEPOINT; + attr.config = id; + attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | + PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD; + attr.sample_period = 1; + attr.size = sizeof(attr); + attr.disabled = 0; + + kp_perf_event_register(ks, &attr, task, filter, cl); + } + } + + if (sep && (*(sep + 1) != '\0')) { + start = sep + 1; + goto again; + } + + return 0; +} + +static int ktap_lib_probe_end(ktap_state *ks) +{ + kp_arg_check(ks, 1, KTAP_TFUNCTION); + + G(ks)->trace_end_closure = clvalue(kp_arg(ks, 1)); + return 0; +} + +static int ktap_lib_traceoff(ktap_state *ks) +{ + end_probes(ks); + + /* call trace_end_closure after probed end */ + if (G(ks)->trace_end_closure) { + setcllvalue(ks->top, G(ks)->trace_end_closure); + incr_top(ks); + kp_call(ks, ks->top - 1, 0); + G(ks)->trace_end_closure = NULL; + } + + return 0; +} + +void kp_probe_exit(ktap_state *ks) +{ + if (!G(ks)->trace_enabled) + return; + + end_probes(ks); + + /* call trace_end_closure after probed end */ + if (!G(ks)->error && G(ks)->trace_end_closure) { + setcllvalue(ks->top, G(ks)->trace_end_closure); + incr_top(ks); + kp_call(ks, ks->top - 1, 0); + G(ks)->trace_end_closure = NULL; + } + + G(ks)->trace_enabled = 0; +} + +int kp_probe_init(ktap_state *ks) +{ + G(ks)->trace_enabled = 1; + return 0; +} + +static const ktap_Reg kdebuglib_funcs[] = { + {"probe_by_id", ktap_lib_probe_by_id}, + {"probe_end", ktap_lib_probe_end}, + {"traceoff", ktap_lib_traceoff}, + {NULL} +}; + +void kp_init_kdebuglib(ktap_state *ks) +{ + kp_ftrace_profile_set_filter = + (void *)kallsyms_lookup_name("ftrace_profile_set_filter"); + if (!kp_ftrace_profile_set_filter) { + printk("ktap: cannot lookup ftrace_profile_set_filter " + "in kallsyms\n"); + return; + } + + kp_register_lib(ks, "kdebug", kdebuglib_funcs); +} + diff --git a/drivers/staging/ktap/interpreter/library/timer.c b/drivers/staging/ktap/interpreter/library/timer.c new file mode 100644 index 000000000000..759f917b3658 --- /dev/null +++ b/drivers/staging/ktap/interpreter/library/timer.c @@ -0,0 +1,192 @@ +/* + * timer.c - timer library support for ktap + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/ctype.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include "../../include/ktap.h" + +struct hrtimer_ktap { + struct hrtimer timer; + ktap_state *ks; + ktap_closure *cl; + u64 ns; + struct list_head list; +}; + +/* + * Currently ktap disallow tracing event in timer callback closure, + * that will corrupt ktap_state and ktap stack, because timer closure + * and event closure use same irq percpu ktap_state and stack. + * We can use a different percpu ktap_state and stack for timer purpuse, + * but that's don't bring any big value with cost on memory consuming. + * + * So just simply disable tracing in timer closure, + * get_recursion_context()/put_recursion_context() is used for this purpose. + * + * option: export perf_swevent_put_recursion_context to slove this issue. + */ +static enum hrtimer_restart hrtimer_ktap_fn(struct hrtimer *timer) +{ + struct hrtimer_ktap *t; + ktap_state *ks; + int rctx; + + rcu_read_lock_sched_notrace(); + rctx = get_recursion_context(); + + t = container_of(timer, struct hrtimer_ktap, timer); + + ks = kp_newthread(t->ks); + setcllvalue(ks->top, t->cl); + incr_top(ks); + kp_call(ks, ks->top - 1, 0); + kp_exitthread(ks); + + hrtimer_add_expires_ns(timer, t->ns); + + put_recursion_context(rctx); + rcu_read_unlock_sched_notrace(); + + return HRTIMER_RESTART; +} + +static void set_tick_timer(ktap_state *ks, u64 period, ktap_closure *cl) +{ + struct hrtimer_ktap *t; + + t = kp_malloc(ks, sizeof(*t)); + t->ks = ks; + t->cl = cl; + t->ns = period; + + INIT_LIST_HEAD(&t->list); + list_add(&t->list, &(G(ks)->timers)); + + hrtimer_init(&t->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + t->timer.function = hrtimer_ktap_fn; + hrtimer_start(&t->timer, ns_to_ktime(period), HRTIMER_MODE_REL); +} + +static void set_profile_timer(ktap_state *ks, u64 period, ktap_closure *cl) +{ + struct perf_event_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.type = PERF_TYPE_SOFTWARE; + attr.config = PERF_COUNT_SW_CPU_CLOCK; + attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | + PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD; + attr.sample_period = period; + attr.size = sizeof(attr); + attr.disabled = 0; + + kp_perf_event_register(ks, &attr, NULL, NULL, cl); +} + +static int do_tick_profile(ktap_state *ks, int is_tick) +{ + const char *str, *tmp; + char interval_str[32] = {0}; + char suffix[10] = {0}; + int n, i = 0; + int factor; + + kp_arg_check(ks, 1, KTAP_TSTRING); + kp_arg_check(ks, 2, KTAP_TFUNCTION); + + str = svalue(kp_arg(ks, 1)); + tmp = str; + while (isdigit(*tmp)) + tmp++; + + strncpy(interval_str, str, tmp - str); + if (kstrtoint(interval_str, 10, &n)) + goto error; + + strncpy(suffix, tmp, 9); + while (suffix[i] != ' ' && suffix[i] != '\0') + i++; + + suffix[i] = '\0'; + + if (!strcmp(suffix, "s") || !strcmp(suffix, "sec")) + factor = NSEC_PER_SEC; + else if (!strcmp(suffix, "ms") || !strcmp(suffix, "msec")) + factor = NSEC_PER_MSEC; + else if (!strcmp(suffix, "us") || !strcmp(suffix, "usec")) + factor = NSEC_PER_USEC; + else + goto error; + + if (is_tick) + set_tick_timer(ks, (u64)factor * n, clvalue(kp_arg(ks, 2))); + else + set_profile_timer(ks, (u64)factor * n, clvalue(kp_arg(ks, 2))); + + return 0; + + error: + kp_error(ks, "cannot parse timer interval: %s\n", str); + return -1; +} + +/* + * tick-n probes fire on only one CPU per interval. + * valid time suffixes: sec/s, msec/ms, usec/us + */ +static int ktap_lib_tick(ktap_state *ks) +{ + return do_tick_profile(ks, 1); +} + +/* + * A profile-n probe fires every fixed interval on every CPU + * valid time suffixes: sec/s, msec/ms, usec/us + */ +static int ktap_lib_profile(ktap_state *ks) +{ + return do_tick_profile(ks, 0); +} + +void kp_exit_timers(ktap_state *ks) +{ + struct hrtimer_ktap *t, *tmp; + struct list_head *timers_list = &(G(ks)->timers); + + list_for_each_entry_safe(t, tmp, timers_list, list) { + hrtimer_cancel(&t->timer); + kp_free(ks, t); + } +} + +static const ktap_Reg timerlib_funcs[] = { + {"profile", ktap_lib_profile}, + {"tick", ktap_lib_tick}, + {NULL} +}; + +void kp_init_timerlib(ktap_state *ks) +{ + kp_register_lib(ks, "timer", timerlib_funcs); +} + diff --git a/drivers/staging/ktap/interpreter/loader.c b/drivers/staging/ktap/interpreter/loader.c new file mode 100644 index 000000000000..0da54d7ef146 --- /dev/null +++ b/drivers/staging/ktap/interpreter/loader.c @@ -0,0 +1,310 @@ +/* + * loader.c - loader for ktap bytecode chunk file + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/slab.h> +#include "../include/ktap.h" + +#define KTAPC_TAIL "\x19\x93\r\n\x1a\n" + +struct load_state { + unsigned char *buff; + int pos; + ktap_state *ks; +}; + +#define READ_CHAR(S) (S->buff[S->pos++]) +#define READ_BYTE(S) READ_CHAR(S) +#define READ_INT(S) load_int(S) +#define READ_NUMBER(S) load_number(S) +#define READ_STRING(S) load_string(S) +#define READ_VECTOR(S, dst, size) \ + do { \ + memcpy(dst, &S->buff[S->pos], size); \ + S->pos += size; \ + } while(0) + +#define NEW_VECTOR(S, size) kp_malloc(S->ks, size) +#define GET_CURRENT(S) &S->buff[S->pos] +#define ADD_POS(S, size) S->pos += size + + +static int load_function(struct load_state *S, ktap_proto *f); + + +static int load_int(struct load_state *S) +{ + int x; + + READ_VECTOR(S, &x, sizeof(int)); + return x; +} + +static int load_number(struct load_state *S) +{ + int x; + + READ_VECTOR(S, &x, sizeof(ktap_number)); + return x; +} + +static ktap_string *load_string(struct load_state *S) +{ + ktap_string *ts; + size_t size; + + size = READ_INT(S); + + if (!size) + return NULL; + else { + char *s = GET_CURRENT(S); + ADD_POS(S, size); + /* remove trailing '\0' */ + ts = kp_tstring_newlstr(S->ks, s, size - 1); + return ts; + } +} + + +static int load_code(struct load_state *S, ktap_proto *f) +{ + int n = READ_INT(S); + + f->sizecode = n; + f->code = NEW_VECTOR(S, n * sizeof(ktap_instruction)); + READ_VECTOR(S, f->code, n * sizeof(ktap_instruction)); + + return 0; +} + +static int load_constants(struct load_state *S, ktap_proto *f) +{ + int i,n; + + n = READ_INT(S); + + f->sizek = n; + f->k = NEW_VECTOR(S, n * sizeof(ktap_value)); + for (i = 0; i < n; i++) + setnilvalue(&f->k[i]); + + for (i=0; i < n; i++) { + ktap_value *o = &f->k[i]; + + int t = READ_CHAR(S); + switch (t) { + case KTAP_TNIL: + setnilvalue(o); + break; + case KTAP_TBOOLEAN: + setbvalue(o, READ_CHAR(S)); + break; + case KTAP_TNUMBER: + /* + * todo: kernel not support fp, check double when + * loading + */ + setnvalue(o, READ_NUMBER(S)); + break; + case KTAP_TSTRING: + setsvalue(o, READ_STRING(S)); + break; + default: + kp_error(S->ks, "ktap: load_constants: " + "unknow ktap_value\n"); + return -1; + + } + } + + n = READ_INT(S); + f->p = NEW_VECTOR(S, n * sizeof(ktap_proto)); + f->sizep = n; + for (i = 0; i < n; i++) + f->p[i] = NULL; + for (i = 0; i < n; i++) { + f->p[i] = kp_newproto(S->ks); + if (load_function(S, f->p[i])) + return -1; + } + + return 0; +} + + +static int load_upvalues(struct load_state *S, ktap_proto *f) +{ + int i,n; + + n = READ_INT(S); + f->upvalues = NEW_VECTOR(S, n * sizeof(ktap_upvaldesc)); + f->sizeupvalues = n; + + for (i = 0; i < n; i++) + f->upvalues[i].name = NULL; + + for (i = 0; i < n; i++) { + f->upvalues[i].instack = READ_BYTE(S); + f->upvalues[i].idx = READ_BYTE(S); + } + + return 0; +} + +static int load_debuginfo(struct load_state *S, ktap_proto *f) +{ + int i,n; + + f->source = READ_STRING(S); + n = READ_INT(S); + f->sizelineinfo = n; + f->lineinfo = NEW_VECTOR(S, n * sizeof(int)); + READ_VECTOR(S, f->lineinfo, n * sizeof(int)); + n = READ_INT(S); + f->locvars = NEW_VECTOR(S, n * sizeof(struct ktap_locvar)); + f->sizelocvars = n; + for (i = 0; i < n; i++) + f->locvars[i].varname = NULL; + for (i = 0; i < n; i++) { + f->locvars[i].varname = READ_STRING(S); + f->locvars[i].startpc = READ_INT(S); + f->locvars[i].endpc = READ_INT(S); + } + n = READ_INT(S); + for (i = 0; i < n; i++) + f->upvalues[i].name = READ_STRING(S); + + return 0; +} + +static int load_function(struct load_state *S, ktap_proto *f) +{ + f->linedefined = READ_INT(S); + f->lastlinedefined = READ_INT(S); + f->numparams = READ_BYTE(S); + f->is_vararg = READ_BYTE(S); + f->maxstacksize = READ_BYTE(S); + if (load_code(S, f)) + return -1; + if (load_constants(S, f)) + return -1; + if (load_upvalues(S, f)) + return -1; + if (load_debuginfo(S, f)) + return -1; + + return 0; +} + + +#define error(S, why) \ + kp_error(S->ks, "load failed: %s precompiled chunk\n", why) + +#define N0 KTAPC_HEADERSIZE +#define N1 (sizeof(KTAP_SIGNATURE) - sizeof(char)) +#define N2 N1 + 2 +#define N3 N2 + 6 + +static int load_header(struct load_state *S) +{ + u8 h[KTAPC_HEADERSIZE]; + u8 s[KTAPC_HEADERSIZE]; + + kp_header(h); + READ_VECTOR(S, s, KTAPC_HEADERSIZE); + + if (memcmp(h, s, N0) == 0) + return 0; + if (memcmp(h, s, N1) != 0) + error(S, "not a"); + else if (memcmp(h, s, N2) != 0) + error(S, "version mismatch in"); + else if (memcmp(h, s, N3) != 0) + error(S, "incompatible"); + else + error(S,"corrupted"); + + return -1; +} + + +static int verify_code(struct load_state *S, ktap_proto *f) +{ + /* not support now */ + return 0; +} + + +ktap_closure *kp_load(ktap_state *ks, unsigned char *buff) +{ + struct load_state S; + ktap_closure *cl; + ktap_lclosure *f; + int ret, i; + + S.ks = ks; + S.buff = buff; + S.pos = 0; + + ret = load_header(&S); + if (ret) + return NULL; + + cl = kp_newlclosure(ks, 1); + if (!cl) + return cl; + + /* put closure on the top, prepare to run with this closure */ + setcllvalue(ks->top, cl); + incr_top(ks); + + cl->l.p = kp_newproto(ks); + if (load_function(&S, cl->l.p)) + return NULL; + + if (cl->l.p->sizeupvalues != 1) { + ktap_proto *p = cl->l.p; + cl = kp_newlclosure(ks, cl->l.p->sizeupvalues); + cl->l.p = p; + setcllvalue(ks->top - 1, cl); + } + + f = &cl->l; + for (i = 0; i < f->nupvalues; i++) { /* initialize upvalues */ + ktap_upval *up = kp_newupval(ks); + f->upvals[i] = up; + } + + /* set global table as 1st upvalue of 'f' */ + if (f->nupvalues == 1) { + ktap_table *reg = hvalue(&G(ks)->registry); + const ktap_value *gt = kp_table_getint(reg, KTAP_RIDX_GLOBALS); + setobj(f->upvals[0]->v, gt); + } + + verify_code(&S, cl->l.p); + return cl; +} + diff --git a/drivers/staging/ktap/interpreter/object.c b/drivers/staging/ktap/interpreter/object.c new file mode 100644 index 000000000000..6538167a2b87 --- /dev/null +++ b/drivers/staging/ktap/interpreter/object.c @@ -0,0 +1,483 @@ +/* + * object.c - ktap object generic operation + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef __KERNEL__ +#include "../include/ktap.h" +#else +#include "../include/ktap_types.h" +#endif + +#ifdef __KERNEL__ + +#define KTAP_ALLOC_FLAGS ((GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN) \ + & ~__GFP_WAIT) + +void *kp_malloc(ktap_state *ks, int size) +{ + void *addr; + + /* + * Normally we don't want to trace under memory pressure, + * so we use a simple rule to handle memory allocation failure: + * + * retry until allocation success, this will make caller don't need + * to handle the unlikely failure case, then ktap exit. + * + * In this approach, if user find there have memory allocation failure, + * user should re-run the ktap script, or fix the memory pressure + * issue, or figure out why the script need so many memory. + * + * Perhaps return pre-allocated stub memory trunk when allocate failed + * is a better approch? + */ + addr = kmalloc(size, KTAP_ALLOC_FLAGS); + if (unlikely(!addr)) { + kp_error(ks, "kmalloc size %d failed, retry again\n", size); + printk("ktap kmalloc size %d failed, retry again\n", size); + dump_stack(); + while (1) { + addr = kmalloc(size, KTAP_ALLOC_FLAGS); + if (addr) + break; + } + kp_printf(ks, "kmalloc retry success after failed, exit\n"); + } + + return addr; +} + +void kp_free(ktap_state *ks, void *addr) +{ + kfree(addr); +} + +void *kp_reallocv(ktap_state *ks, void *addr, int oldsize, int newsize) +{ + void *new_addr; + + new_addr = krealloc(addr, newsize, KTAP_ALLOC_FLAGS); + if (unlikely(!new_addr)) { + kp_error(ks, "krealloc size %d failed, retry again\n", newsize); + printk("ktap krealloc size %d failed, retry again\n", newsize); + dump_stack(); + while (1) { + new_addr = krealloc(addr, newsize, KTAP_ALLOC_FLAGS); + if (new_addr) + break; + } + kp_printf(ks, "krealloc retry success after failed, exit\n"); + } + + return new_addr; +} + +void *kp_zalloc(ktap_state *ks, int size) +{ + void *addr; + + addr = kzalloc(size, KTAP_ALLOC_FLAGS); + if (unlikely(!addr)) { + kp_error(ks, "kzalloc size %d failed, retry again\n", size); + printk("ktap kzalloc size %d failed, retry again\n", size); + dump_stack(); + while (1) { + addr = kzalloc(size, KTAP_ALLOC_FLAGS); + if (addr) + break; + } + kp_printf(ks, "kzalloc retry success after failed, exit\n"); + } + + return addr; +} +#endif + +void kp_obj_dump(ktap_state *ks, const ktap_value *v) +{ + switch (ttype(v)) { + case KTAP_TNIL: + kp_puts(ks, "NIL"); + break; + case KTAP_TNUMBER: + kp_printf(ks, "NUMBER %ld", nvalue(v)); + break; + case KTAP_TBOOLEAN: + kp_printf(ks, "BOOLEAN %d", bvalue(v)); + break; + case KTAP_TLIGHTUSERDATA: + kp_printf(ks, "LIGHTUSERDATA 0x%lx", (unsigned long)pvalue(v)); + break; + case KTAP_TLCF: + kp_printf(ks, "LIGHTCFCUNTION 0x%lx", (unsigned long)fvalue(v)); + break; + case KTAP_TSHRSTR: + case KTAP_TLNGSTR: + kp_printf(ks, "SHRSTR #%s", svalue(v)); + break; + case KTAP_TUSERDATA: + kp_printf(ks, "USERDATA 0x%lx", (unsigned long)uvalue(v)); + break; + case KTAP_TTABLE: + kp_printf(ks, "TABLE 0x%lx", (unsigned long)hvalue(v)); + break; + default: + kp_printf(ks, "GCVALUE 0x%lx", (unsigned long)gcvalue(v)); + break; + } +} + +#ifdef __KERNEL__ +#include <linux/stacktrace.h> +#include <linux/kallsyms.h> + +static void kp_btrace_dump(ktap_state *ks, ktap_btrace *bt) +{ + char str[KSYM_SYMBOL_LEN]; + int i; + + for (i = 0; i < bt->nr_entries; i++) { + unsigned long p = bt->entries[i]; + + if (p == ULONG_MAX) + break; + + SPRINT_SYMBOL(str, p); + kp_printf(ks, "%s\n", str); + } +} + +static int kp_btrace_equal(ktap_btrace *bt1, ktap_btrace *bt2) +{ + int i; + + if (bt1->nr_entries != bt2->nr_entries) + return 0; + + for (i = 0; i < bt1->nr_entries; i++) { + if (bt1->entries[i] != bt2->entries[i]) + return 0; + } + + return 1; +} +#endif + +void kp_showobj(ktap_state *ks, const ktap_value *v) +{ + switch (ttype(v)) { + case KTAP_TNIL: + kp_puts(ks, "nil"); + break; + case KTAP_TNUMBER: + kp_printf(ks, "%ld", nvalue(v)); + break; + case KTAP_TBOOLEAN: + kp_puts(ks, (bvalue(v) == 1) ? "true" : "false"); + break; + case KTAP_TLIGHTUSERDATA: + kp_printf(ks, "0x%lx", (unsigned long)pvalue(v)); + break; + case KTAP_TLCF: + kp_printf(ks, "0x%lx", (unsigned long)fvalue(v)); + break; + case KTAP_TSHRSTR: + case KTAP_TLNGSTR: + kp_puts(ks, svalue(v)); + break; + case KTAP_TUSERDATA: + kp_printf(ks, "0x%lx", (unsigned long)uvalue(v)); + break; + case KTAP_TTABLE: + kp_table_dump(ks, hvalue(v)); + break; +#ifdef __KERNEL__ + case KTAP_TEVENT: + kp_transport_event_write(ks, evalue(v)); + break; + case KTAP_TBTRACE: + kp_btrace_dump(ks, btvalue(v)); + break; + case KTAP_TAGGRTABLE: + kp_aggrtable_dump(ks, ahvalue(v)); + break; + case KTAP_TAGGRACCVAL: + kp_aggraccval_dump(ks, aggraccvalue(v)); + break; +#endif + default: + kp_error(ks, "print unknown value type: %d\n", ttype(v)); + break; + } +} + + +/* + * equality of ktap values. ks == NULL means raw equality + */ +int kp_equalobjv(ktap_state *ks, const ktap_value *t1, const ktap_value *t2) +{ + switch (ttype(t1)) { + case KTAP_TNIL: + return 1; + case KTAP_TNUMBER: + return nvalue(t1) == nvalue(t2); + case KTAP_TBOOLEAN: + return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ + case KTAP_TLIGHTUSERDATA: + return pvalue(t1) == pvalue(t2); + case KTAP_TLCF: + return fvalue(t1) == fvalue(t2); + case KTAP_TSHRSTR: + return eqshrstr(rawtsvalue(t1), rawtsvalue(t2)); + case KTAP_TLNGSTR: + return kp_tstring_eqlngstr(rawtsvalue(t1), rawtsvalue(t2)); + case KTAP_TUSERDATA: + if (uvalue(t1) == uvalue(t2)) + return 1; + else if (ks == NULL) + return 0; + case KTAP_TTABLE: + if (hvalue(t1) == hvalue(t2)) + return 1; + else if (ks == NULL) + return 0; +#ifdef __KERNEL__ + case KTAP_TBTRACE: + return kp_btrace_equal(btvalue(t1), btvalue(t2)); +#endif + default: + return gcvalue(t1) == gcvalue(t2); + } + + return 0; +} + +/* + * ktap will not use lua's length operator on table meaning, + * also # is not for length operator any more in ktap. + * + * Quote from lua mannal: + * 2.5.5 - The Length Operator + * + * The length operator is denoted by the unary operator #. + * The length of a string is its number of bytes(that is, + * the usual meaning of string length when each character is one byte). + * + * The length of a table t is defined to be any integer index n + * such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, + * n can be zero. For a regular array, with non-nil values from 1 to a given n, + * its length is exactly that n, the index of its last value. If the array has + * "holes" (that is, nil values between other non-nil values), then #t can be + * any of the indices that directly precedes a nil value + * (that is, it may consider any such nil value as the end of the array). + */ +int kp_objlen(ktap_state *ks, const ktap_value *v) +{ + switch(v->type) { + case KTAP_TTABLE: + return kp_table_length(ks, hvalue(v)); + case KTAP_TSTRING: + return rawtsvalue(v)->tsv.len; + default: + kp_printf(ks, "cannot get length of type %d\n", v->type); + return -1; + } + return 0; +} + +/* need to protect allgc field? */ +ktap_gcobject *kp_newobject(ktap_state *ks, int type, size_t size, + ktap_gcobject **list) +{ + ktap_gcobject *o; + + o = kp_malloc(ks, size); + if (list == NULL) + list = &G(ks)->allgc; + + gch(o)->tt = type; + gch(o)->next = *list; + *list = o; + + return o; +} + +ktap_upval *kp_newupval(ktap_state *ks) +{ + ktap_upval *uv; + + uv = &kp_newobject(ks, KTAP_TUPVAL, sizeof(ktap_upval), NULL)->uv; + uv->v = &uv->u.value; + setnilvalue(uv->v); + return uv; +} + +static ktap_btrace *kp_newbacktrace(ktap_state *ks, ktap_gcobject **list) +{ + ktap_btrace *bt; + + bt = &kp_newobject(ks, KTAP_TBTRACE, sizeof(ktap_btrace), list)->bt; + return bt; +} + +void kp_objclone(ktap_state *ks, const ktap_value *o, ktap_value *newo, + ktap_gcobject **list) +{ + if (ttisbtrace(o)) { + ktap_btrace *bt; + bt = kp_newbacktrace(ks, list); + bt->nr_entries = btvalue(o)->nr_entries; + memcpy(&bt->entries[0], &btvalue(o)->entries[0], + sizeof(bt->entries)); + setbtvalue(newo, bt); + } else { + kp_error(ks, "cannot clone ktap value type %d\n", ttype(o)); + setnilvalue(newo); + } +} + +ktap_closure *kp_newlclosure(ktap_state *ks, int n) +{ + ktap_closure *cl; + + cl = (ktap_closure *)kp_newobject(ks, KTAP_TLCL, sizeof(*cl), NULL); + cl->l.p = NULL; + cl->l.nupvalues = n; + while (n--) + cl->l.upvals[n] = NULL; + + return cl; +} + +static void free_proto(ktap_state *ks, ktap_proto *f) +{ + kp_free(ks, f->code); + kp_free(ks, f->p); + kp_free(ks, f->k); + kp_free(ks, f->lineinfo); + kp_free(ks, f->locvars); + kp_free(ks, f->upvalues); + kp_free(ks, f); +} + +ktap_proto *kp_newproto(ktap_state *ks) +{ + ktap_proto *f; + f = (ktap_proto *)kp_newobject(ks, KTAP_TPROTO, sizeof(*f), NULL); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->cache = NULL; + f->sizecode = 0; + f->lineinfo = NULL; + f->sizelineinfo = 0; + f->upvalues = NULL; + f->sizeupvalues = 0; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->locvars = NULL; + f->sizelocvars = 0; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + +static ktap_udata *newudata(ktap_state *ks, size_t s) +{ + ktap_udata *u; + + u = &kp_newobject(ks, KTAP_TUSERDATA, sizeof(ktap_udata) + s, NULL)->u; + u->uv.len = s; + return u; +} + +void *kp_newuserdata(ktap_state *ks, size_t size) +{ + ktap_udata *u; + + u = newudata(ks, size); + return u + 1; +} + +void kp_free_gclist(ktap_state *ks, ktap_gcobject *o) +{ + while (o) { + ktap_gcobject *next; + + next = gch(o)->next; + switch (gch(o)->tt) { + case KTAP_TTABLE: + kp_table_free(ks, (ktap_table *)o); + break; + case KTAP_TPROTO: + free_proto(ks, (ktap_proto *)o); + break; +#ifdef __KERNEL__ + case KTAP_TAGGRTABLE: + kp_aggrtable_free(ks, (ktap_aggrtable *)o); + break; +#endif + default: + kp_free(ks, o); + } + o = next; + } +} + +void kp_free_all_gcobject(ktap_state *ks) +{ + kp_free_gclist(ks, G(ks)->allgc); + G(ks)->allgc = NULL; +} + +/******************************************************************************/ + +/* + * make header for precompiled chunks + * if you change the code below be sure to update load_header and FORMAT above + * and KTAPC_HEADERSIZE in ktap_types.h + */ +void kp_header(u8 *h) +{ + int x = 1; + + memcpy(h, KTAP_SIGNATURE, sizeof(KTAP_SIGNATURE) - sizeof(char)); + h += sizeof(KTAP_SIGNATURE) - sizeof(char); + *h++ = (u8)VERSION; + *h++ = (u8)FORMAT; + *h++ = (u8)(*(char*)&x); /* endianness */ + *h++ = (u8)(sizeof(int)); + *h++ = (u8)(sizeof(size_t)); + *h++ = (u8)(sizeof(ktap_instruction)); + *h++ = (u8)(sizeof(ktap_number)); + *h++ = (u8)(((ktap_number)0.5) == 0); /* is ktap_number integral? */ + memcpy(h, KTAPC_TAIL, sizeof(KTAPC_TAIL) - sizeof(char)); +} + + diff --git a/drivers/staging/ktap/interpreter/opcode.c b/drivers/staging/ktap/interpreter/opcode.c new file mode 100644 index 000000000000..2f44855fcad2 --- /dev/null +++ b/drivers/staging/ktap/interpreter/opcode.c @@ -0,0 +1,127 @@ +/* + * opcode.c + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "../include/ktap_types.h" +#include "../include/ktap_opcodes.h" + +const char *const ktap_opnames[NUM_OPCODES + 1] = { + "MOVE", + "LOADK", + "LOADKX", + "LOADBOOL", + "LOADNIL", + "GETUPVAL", + "GETTABUP", + "GETTABLE", + "SETTABUP", + "SETTABUP_INCR", + "SETUPVAL", + "SETTABLE", + "SETTABLE_INCR", + "NEWTABLE", + "SELF", + "ADD", + "SUB", + "MUL", + "DIV", + "MOD", + "POW", + "UNM", + "NOT", + "LEN", + "CONCAT", + "JMP", + "EQ", + "LT", + "LE", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "FORLOOP", + "FORPREP", + "TFORCALL", + "TFORLOOP", + "SETLIST", + "CLOSURE", + "VARARG", + "EXTRAARG", + + "EVENT", + "EVENT_NAME", + "EVENT_ARG", /* arg1, arg2 .. arg9 */ + NULL +}; + + +#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) + +const u8 ktap_opmodes[NUM_OPCODES] = { +/* T A B C mode opcode */ + opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ + ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ + ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ + ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ + ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ + ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ + ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ + ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ + ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_EVENT */ +}; + + diff --git a/drivers/staging/ktap/interpreter/strfmt.c b/drivers/staging/ktap/interpreter/strfmt.c new file mode 100644 index 000000000000..2c1e7618fef4 --- /dev/null +++ b/drivers/staging/ktap/interpreter/strfmt.c @@ -0,0 +1,196 @@ +/* + * strfmt.c - printf implementation + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/ctype.h> +#include <linux/kallsyms.h> +#include "../include/ktap.h" + +/* macro to `unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + +#define L_ESC '%' + +/* valid flags in a format specification */ +#define FLAGS "-+ #0" + +#define INTFRMLEN "ll" +#define INTFRM_T long long + +/* + * maximum size of each format specification (such as '%-099.99d') + * (+10 accounts for %99.99x plus margin of error) + */ +#define MAX_FORMAT (sizeof(FLAGS) + sizeof(INTFRMLEN) + 10) + +static const char *scanformat(ktap_state *ks, const char *strfrmt, char *form) +{ + const char *p = strfrmt; + while (*p != '\0' && strchr(FLAGS, *p) != NULL) + p++; /* skip flags */ + + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) { + kp_error(ks, "invalid format (repeated flags)\n"); + return NULL; + } + + if (isdigit(uchar(*p))) + p++; /* skip width */ + + if (isdigit(uchar(*p))) + p++; /* (2 digits at most) */ + + if (*p == '.') { + p++; + if (isdigit(uchar(*p))) + p++; /* skip precision */ + if (isdigit(uchar(*p))) + p++; /* (2 digits at most) */ + } + + if (isdigit(uchar(*p))) { + kp_error(ks, "invalid format (width or precision too long)\n"); + return NULL; + } + + *(form++) = '%'; + memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); + form += p - strfrmt + 1; + *form = '\0'; + return p; +} + + +/* + * add length modifier into formats + */ +static void addlenmod(char *form, const char *lenmod) +{ + size_t l = strlen(form); + size_t lm = strlen(lenmod); + char spec = form[l - 1]; + + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; +} + + +static void ktap_argerror(ktap_state *ks, int narg, const char *extramsg) +{ + kp_error(ks, "bad argument #%d: (%s)\n", narg, extramsg); +} + +int kp_strfmt(ktap_state *ks, struct trace_seq *seq) +{ + int arg = 1; + size_t sfl; + ktap_value *arg_fmt = kp_arg(ks, 1); + int argnum = kp_arg_nr(ks); + const char *strfrmt, *strfrmt_end; + + strfrmt = svalue(arg_fmt); + sfl = rawtsvalue(arg_fmt)->tsv.len; + strfrmt_end = strfrmt + sfl; + + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + trace_seq_putc(seq, *strfrmt++); + else if (*++strfrmt == L_ESC) + trace_seq_putc(seq, *strfrmt++); + else { /* format item */ + char form[MAX_FORMAT]; + + if (++arg > argnum) { + ktap_argerror(ks, arg, "no value"); + return -1; + } + + strfrmt = scanformat(ks, strfrmt, form); + switch (*strfrmt++) { + case 'c': + trace_seq_printf(seq, form, + nvalue(kp_arg(ks, arg))); + break; + case 'd': case 'i': { + ktap_number n = nvalue(kp_arg(ks, arg)); + INTFRM_T ni = (INTFRM_T)n; + addlenmod(form, INTFRMLEN); + trace_seq_printf(seq, form, ni); + break; + } + case 'p': { + char str[KSYM_SYMBOL_LEN]; + SPRINT_SYMBOL(str, nvalue(kp_arg(ks, arg))); + trace_seq_puts(seq, str); + break; + } + case 'o': case 'u': case 'x': case 'X': { + ktap_number n = nvalue(kp_arg(ks, arg)); + unsigned INTFRM_T ni = (unsigned INTFRM_T)n; + addlenmod(form, INTFRMLEN); + trace_seq_printf(seq, form, ni); + break; + } + case 's': { + ktap_value *v = kp_arg(ks, arg); + const char *s; + size_t l; + + if (isnil(v)) { + trace_seq_puts(seq, "nil"); + return 0; + } + + if (ttisevent(v)) { + kp_event_tostring(ks, seq); + return 0; + } + + s = svalue(v); + l = rawtsvalue(v)->tsv.len; + if (!strchr(form, '.') && l >= 100) { + /* + * no precision and string is too long + * to be formatted; + * keep original string + */ + trace_seq_puts(seq, s); + break; + } else { + trace_seq_printf(seq, form, s); + break; + } + } + default: /* also treat cases `pnLlh' */ + kp_error(ks, "invalid option " KTAP_QL("%%%c") + " to " KTAP_QL("format"), + *(strfrmt - 1)); + } + } + } + + return 0; +} + diff --git a/drivers/staging/ktap/interpreter/table.c b/drivers/staging/ktap/interpreter/table.c new file mode 100644 index 000000000000..4e83947ba02d --- /dev/null +++ b/drivers/staging/ktap/interpreter/table.c @@ -0,0 +1,1292 @@ +/* + * table.c - ktap table data structure manipulation function + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef __KERNEL__ +#include "../include/ktap.h" +#include <linux/spinlock.h> +#include <linux/kallsyms.h> +#include <linux/sort.h> +#else +#include "../include/ktap_types.h" + +static inline void sort(void *base, size_t num, size_t size, + int (*cmp_func)(const void *, const void *), + void (*swap_func)(void *, void *, int size)) +{} +#endif + + +#ifdef __KERNEL__ +#define kp_table_lock_init(t) \ + do { \ + t->lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \ + } while (0) +#define kp_table_lock(t) \ + do { \ + local_irq_save(flags); \ + arch_spin_lock(&t->lock); \ + } while (0) +#define kp_table_unlock(t) \ + do { \ + arch_spin_unlock(&t->lock); \ + local_irq_restore(flags); \ + } while (0) + +#else +#define kp_table_lock_init(t) +#define kp_table_lock(t) +#define kp_table_unlock(t) +#endif + +#define MAXBITS 30 +#define MAXASIZE (1 << MAXBITS) + + +#define NILCONSTANT {NULL}, KTAP_TNIL +const struct ktap_value ktap_nilobjectv = {NILCONSTANT}; +#define ktap_nilobject (&ktap_nilobjectv) + +static const ktap_tnode dummynode_ = { + {NILCONSTANT}, /* value */ + {{NILCONSTANT, NULL}}, /* key */ +}; + +#define gnode(t,i) (&(t)->node[i]) +#define gkey(n) (&(n)->i_key.tvk) +#define gval(n) (&(n)->i_val) +#define gnext(n) ((n)->i_key.nk.next) + +#define twoto(x) (1<<(x)) +#define sizenode(t) (twoto((t)->lsizenode)) + +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) + +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + +#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#define hashboolean(t,p) hashpow2(t, p) +#define hashnum(t, n) hashmod(t, (unsigned int)n) +#define hashpointer(t,p) hashmod(t, (unsigned long)(p)) + +#define dummynode (&dummynode_) +#define isdummy(n) ((n) == dummynode) + +static void table_setint(ktap_state *ks, ktap_table *t, int key, ktap_value *v); +static ktap_value *table_set(ktap_state *ks, ktap_table *t, + const ktap_value *key); +static void setnodevector(ktap_state *ks, ktap_table *t, int size); + +static int ceillog2(unsigned int x) +{ + static const u8 log_2[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + + int l = 0; + + x--; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; +} + + +ktap_table *kp_table_new(ktap_state *ks) +{ + ktap_table *t = &kp_newobject(ks, KTAP_TTABLE, sizeof(ktap_table), + NULL)->h; + t->flags = (u8)(~0); + t->array = NULL; + t->sizearray = 0; + t->node = (ktap_tnode *)dummynode; + t->gclist = NULL; + setnodevector(ks, t, 0); + + kp_table_lock_init(t); + return t; +} + +static const ktap_value *table_getint(ktap_table *t, int key) +{ + ktap_tnode *n; + + if ((unsigned int)(key - 1) < (unsigned int)t->sizearray) + return &t->array[key - 1]; + + n = hashnum(t, key); + do { + if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == key) + return gval(n); + else + n = gnext(n); + } while (n); + + return ktap_nilobject; +} + +const ktap_value *kp_table_getint(ktap_table *t, int key) +{ + const ktap_value *val; + unsigned long __maybe_unused flags; + + kp_table_lock(t); + val = table_getint(t, key); + kp_table_unlock(t); + + return val; +} + +static ktap_tnode *mainposition (const ktap_table *t, const ktap_value *key) +{ + switch (ttype(key)) { + case KTAP_TNUMBER: + return hashnum(t, nvalue(key)); + case KTAP_TLNGSTR: { + ktap_string *s = rawtsvalue(key); + if (s->tsv.extra == 0) { /* no hash? */ + s->tsv.hash = kp_string_hash(getstr(s), s->tsv.len, + s->tsv.hash); + s->tsv.extra = 1; /* now it has its hash */ + } + return hashstr(t, rawtsvalue(key)); + } + case KTAP_TSHRSTR: + return hashstr(t, rawtsvalue(key)); + case KTAP_TBOOLEAN: + return hashboolean(t, bvalue(key)); + case KTAP_TLIGHTUSERDATA: + return hashpointer(t, pvalue(key)); + case KTAP_TLCF: + return hashpointer(t, fvalue(key)); + case KTAP_TBTRACE: + /* use first entry as hash key, cannot use gcvalue as key */ + return hashpointer(t, btvalue(key)->entries[0]); + default: + return hashpointer(t, gcvalue(key)); + } +} + +static int arrayindex(const ktap_value *key) +{ + if (ttisnumber(key)) { + ktap_number n = nvalue(key); + int k = (int)n; + if ((ktap_number)k == n) + return k; + } + + /* `key' did not match some condition */ + return -1; +} + +/* + * returns the index of a `key' for table traversals. First goes all + * elements in the array part, then elements in the hash part. The + * beginning of a traversal is signaled by -1. + */ +static int findindex(ktap_state *ks, ktap_table *t, StkId key) +{ + int i; + + if (ttisnil(key)) + return -1; /* first iteration */ + + i = arrayindex(key); + if (i > 0 && i <= t->sizearray) /* is `key' inside array part? */ + return i - 1; /* yes; that's the index (corrected to C) */ + else { + ktap_tnode *n = mainposition(t, key); + for (;;) { /* check whether `key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in `next' */ + if (kp_equalobjv(ks, gkey(n), key)) { + i = n - gnode(t, 0); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return i + t->sizearray; + } else + n = gnext(n); + + if (n == NULL) + /* key not found */ + kp_error(ks, "invalid table key to next"); + } + } +} + +int kp_table_next(ktap_state *ks, ktap_table *t, StkId key) +{ + unsigned long __maybe_unused flags; + int i; + + kp_table_lock(t); + + i = findindex(ks, t, key); /* find original element */ + + for (i++; i < t->sizearray; i++) { /* try first array part */ + if (!ttisnil(&t->array[i])) { /* a non-nil value? */ + setnvalue(key, i+1); + setobj(key+1, &t->array[i]); + kp_table_unlock(t); + return 1; + } + } + + for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ + if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ + setobj(key, gkey(gnode(t, i))); + setobj(key+1, gval(gnode(t, i))); + kp_table_unlock(t); + return 1; + } + } + + kp_table_unlock(t); + return 0; /* no more elements */ +} + + + +static int computesizes (int nums[], int *narray) +{ + int i; + int twotoi; /* 2^i */ + int a = 0; /* number of elements smaller than 2^i */ + int na = 0; /* number of elements to go to array part */ + int n = 0; /* optimal size for array part */ + + for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { + if (nums[i] > 0) { + a += nums[i]; + /* more than half elements present? */ + if (a > twotoi/2) { + /* optimal size (till now) */ + n = twotoi; + /* + * all elements smaller than n will go to + * array part + */ + na = a; + } + } + if (a == *narray) + break; /* all elements already counted */ + } + *narray = n; + return na; +} + + +static int countint(const ktap_value *key, int *nums) +{ + int k = arrayindex(key); + + /* is `key' an appropriate array index? */ + if (0 < k && k <= MAXASIZE) { + nums[ceillog2(k)]++; /* count as such */ + return 1; + } else + return 0; +} + + +static int numusearray(const ktap_table *t, int *nums) +{ + int lg; + int ttlg; /* 2^lg */ + int ause = 0; /* summation of `nums' */ + int i = 1; /* count to traverse all array keys */ + + /* for each slice */ + for (lg=0, ttlg=1; lg <= MAXBITS; lg++, ttlg *= 2) { + int lc = 0; /* counter */ + int lim = ttlg; + + if (lim > t->sizearray) { + lim = t->sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + + /* count elements in range (2^(lg-1), 2^lg] */ + for (; i <= lim; i++) { + if (!ttisnil(&t->array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; +} + +static int numusehash(const ktap_table *t, int *nums, int *pnasize) +{ + int totaluse = 0; /* total number of elements */ + int ause = 0; /* summation of `nums' */ + int i = sizenode(t); + + while (i--) { + ktap_tnode *n = &t->node[i]; + if (!isnil(gval(n))) { + ause += countint(gkey(n), nums); + totaluse++; + } + } + + *pnasize += ause; + return totaluse; +} + + +static void setarrayvector(ktap_state *ks, ktap_table *t, int size) +{ + int i; + + kp_realloc(ks, t->array, t->sizearray, size, ktap_value); + for (i = t->sizearray; i < size; i++) + setnilvalue(&t->array[i]); + + t->sizearray = size; +} + +static void setnodevector(ktap_state *ks, ktap_table *t, int size) +{ + int lsize; + + if (size == 0) { /* no elements to hash part? */ + t->node = (ktap_tnode *)dummynode; /* use common `dummynode' */ + lsize = 0; + } else { + int i; + lsize = ceillog2(size); + if (lsize > MAXBITS) { + kp_error(ks, "table overflow\n"); + return; + } + + size = twoto(lsize); + t->node = kp_malloc(ks, size * sizeof(ktap_tnode)); + for (i = 0; i < size; i++) { + ktap_tnode *n = gnode(t, i); + gnext(n) = NULL; + setnilvalue(gkey(n)); + setnilvalue(gval(n)); + } + } + + t->lsizenode = (u8)lsize; + t->lastfree = gnode(t, size); /* all positions are free */ +} + +static void table_resize(ktap_state *ks, ktap_table *t, int nasize, int nhsize) +{ + int i; + int oldasize = t->sizearray; + int oldhsize = t->lsizenode; + ktap_tnode *nold = t->node; /* save old hash ... */ + +#ifdef __KERNEL__ + kp_verbose_printf(ks, "table resize, nasize: %d, nhsize: %d\n", + nasize, nhsize); +#endif + + if (nasize > oldasize) /* array part must grow? */ + setarrayvector(ks, t, nasize); + + /* create new hash part with appropriate size */ + setnodevector(ks, t, nhsize); + + if (nasize < oldasize) { /* array part must shrink? */ + t->sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i=nasize; i<oldasize; i++) { + if (!ttisnil(&t->array[i])) + table_setint(ks, t, i + 1, &t->array[i]); + } + + /* shrink array */ + kp_realloc(ks, t->array, oldasize, nasize, ktap_value); + } + + /* re-insert elements from hash part */ + for (i = twoto(oldhsize) - 1; i >= 0; i--) { + ktap_tnode *old = nold+i; + if (!ttisnil(gval(old))) { + /* + * doesn't need barrier/invalidate cache, as entry was + * already present in the table + */ + setobj(table_set(ks, t, gkey(old)), gval(old)); + } + } + + if (!isdummy(nold)) + kp_free(ks, nold); /* free old array */ +} + +void kp_table_resize(ktap_state *ks, ktap_table *t, int nasize, int nhsize) +{ + unsigned long __maybe_unused flags; + + kp_table_lock(t); + table_resize(ks, t, nasize, nhsize); + kp_table_unlock(t); +} + +void kp_table_resizearray(ktap_state *ks, ktap_table *t, int nasize) +{ + unsigned long __maybe_unused flags; + int nsize; + + kp_table_lock(t); + + nsize = isdummy(t->node) ? 0 : sizenode(t); + table_resize(ks, t, nasize, nsize); + + kp_table_unlock(t); +} + +static void rehash(ktap_state *ks, ktap_table *t, const ktap_value *ek) +{ + int nasize, na; + /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */ + int nums[MAXBITS+1]; + int i; + int totaluse; + + for (i = 0; i <= MAXBITS; i++) + nums[i] = 0; /* reset counts */ + + nasize = numusearray(t, nums); /* count keys in array part */ + totaluse = nasize; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ + /* count extra key */ + nasize += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + na = computesizes(nums, &nasize); + /* resize the table to new computed sizes */ + table_resize(ks, t, nasize, totaluse - na); +} + + +static ktap_tnode *getfreepos(ktap_table *t) +{ + while (t->lastfree > t->node) { + t->lastfree--; + if (isnil(gkey(t->lastfree))) + return t->lastfree; + } + return NULL; /* could not find a free place */ +} + + +static ktap_value *table_newkey(ktap_state *ks, ktap_table *t, + const ktap_value *key) +{ + ktap_tnode *mp; + ktap_value newkey; + + mp = mainposition(t, key); + if (!isnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ + ktap_tnode *othern; + ktap_tnode *n = getfreepos(t); /* get a free place */ + if (n == NULL) { /* cannot find a free place? */ + rehash(ks, t, key); /* grow table */ + /* whatever called 'newkey' take care of TM cache and GC barrier */ + return table_set(ks, t, key); /* insert key into grown table */ + } + + othern = mainposition(t, gkey(mp)); + if (othern != mp) { /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (gnext(othern) != mp) + othern = gnext(othern); /* find previous */ + gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ + *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + gnext(mp) = NULL; /* now `mp' is free */ + setnilvalue(gval(mp)); + } else { /* colliding node is in its own main position */ + /* new node will go into free position */ + gnext(n) = gnext(mp); /* chain new position */ + gnext(mp) = n; + mp = n; + } + } + + /* special handling for cloneable object, maily for btrace object */ + if (ttisclone(key)) + kp_objclone(ks, key, &newkey, &t->gclist); + else + newkey = *key; + + setobj(gkey(mp), &newkey); + return gval(mp); +} + + +/* + * search function for short strings + */ +static const ktap_value *table_getstr(ktap_table *t, ktap_string *key) +{ + ktap_tnode *n = hashstr(t, key); + + do { /* check whether `key' is somewhere in the chain */ + if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), + key)) + return gval(n); /* that's it */ + else + n = gnext(n); + } while (n); + + return ktap_nilobject; +} + + +/* + * main search function + */ +static const ktap_value *table_get(ktap_table *t, const ktap_value *key) +{ + switch (ttype(key)) { + case KTAP_TNIL: + return ktap_nilobject; + case KTAP_TSHRSTR: + return table_getstr(t, rawtsvalue(key)); + case KTAP_TNUMBER: { + ktap_number n = nvalue(key); + int k = (int)n; + if ((ktap_number)k == nvalue(key)) /* index is int? */ + return table_getint(t, k); /* use specialized version */ + /* else go through */ + } + default: { + ktap_tnode *n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (rawequalobj(gkey(n), key)) + return gval(n); /* that's it */ + else + n = gnext(n); + } while (n); + + return ktap_nilobject; + } + } +} + +const ktap_value *kp_table_get(ktap_table *t, const ktap_value *key) +{ + const ktap_value *val; + unsigned long __maybe_unused flags; + + kp_table_lock(t); + val = table_get(t, key); + kp_table_unlock(t); + + return val; +} + +static ktap_value *table_set(ktap_state *ks, ktap_table *t, + const ktap_value *key) +{ + const ktap_value *p = table_get(t, key); + + if (p != ktap_nilobject) + return (ktap_value *)p; + else + return table_newkey(ks, t, key); +} + +void kp_table_setvalue(ktap_state *ks, ktap_table *t, + const ktap_value *key, ktap_value *val) +{ + unsigned long __maybe_unused flags; + + if (isnil(key)) { + kp_printf(ks, "table index is nil\n"); + kp_exit(ks); + return; + } + + kp_table_lock(t); + setobj(table_set(ks, t, key), val); + kp_table_unlock(t); +} + +static void table_setint(ktap_state *ks, ktap_table *t, int key, ktap_value *v) +{ + const ktap_value *p; + ktap_value *cell; + + p = table_getint(t, key); + + if (p != ktap_nilobject) + cell = (ktap_value *)p; + else { + ktap_value k; + setnvalue(&k, key); + cell = table_newkey(ks, t, &k); + } + + setobj(cell, v); +} + +void kp_table_setint(ktap_state *ks, ktap_table *t, int key, ktap_value *val) +{ + unsigned long __maybe_unused flags; + + kp_table_lock(t); + table_setint(ks, t, key, val); + kp_table_unlock(t); +} + +void kp_table_atomic_inc(ktap_state *ks, ktap_table *t, ktap_value *key, int n) +{ + unsigned long __maybe_unused flags; + ktap_value *v; + + if (isnil(key)) { + kp_printf(ks, "table index is nil\n"); + kp_exit(ks); + return; + } + + kp_table_lock(t); + + v = table_set(ks, t, key); + if (isnil(v)) { + setnvalue(v, n); + } else + setnvalue(v, nvalue(v) + n); + + kp_table_unlock(t); +} + +int kp_table_length(ktap_state *ks, ktap_table *t) +{ + unsigned long __maybe_unused flags; + int i, len = 0; + + kp_table_lock(t); + + for (i = 0; i < t->sizearray; i++) { + ktap_value *v = &t->array[i]; + + if (isnil(v)) + continue; + len++; + } + + for (i = 0; i < sizenode(t); i++) { + ktap_tnode *n = &t->node[i]; + + if (isnil(gkey(n))) + continue; + + len++; + } + + kp_table_unlock(t); + return len; +} + +void kp_table_free(ktap_state *ks, ktap_table *t) +{ + if (t->sizearray > 0) + kp_free(ks, t->array); + if (!isdummy(t->node)) + kp_free(ks, t->node); + + kp_free_gclist(ks, t->gclist); + kp_free(ks, t); +} + +void kp_table_dump(ktap_state *ks, ktap_table *t) +{ + int i, count = 0; + + kp_puts(ks, "{"); + for (i = 0; i < t->sizearray; i++) { + ktap_value *v = &t->array[i]; + + if (isnil(v)) + continue; + + if (count) + kp_puts(ks, ", "); + + kp_printf(ks, "(%d: ", i + 1); + kp_showobj(ks, v); + kp_puts(ks, ")"); + count++; + } + + for (i = 0; i < sizenode(t); i++) { + ktap_tnode *n = &t->node[i]; + + if (isnil(gkey(n))) + continue; + + if (count) + kp_puts(ks, ", "); + + kp_puts(ks, "("); + kp_showobj(ks, gkey(n)); + kp_puts(ks, ": "); + kp_showobj(ks, gval(n)); + kp_puts(ks, ")"); + count++; + } + kp_puts(ks, "}"); +} + +/* + * table-clear only set nil of all elements, not free t->array and nodes. + * we assume user will reuse table soon after clear table, so reserve array + * and nodes will avoid memory allocation when insert key-value again. + */ +void kp_table_clear(ktap_state *ks, ktap_table *t) +{ + unsigned long __maybe_unused flags; + int i; + + kp_table_lock(t); + + for (i = 0; i < t->sizearray; i++) { + ktap_value *v = &t->array[i]; + + if (isnil(v)) + continue; + + setnilvalue(v); + } + + for (i = 0; i < sizenode(t); i++) { + ktap_tnode *n = &t->node[i]; + + if (isnil(gkey(n))) + continue; + + setnilvalue(gkey(n)); + setnilvalue(gval(n)); + } + + kp_table_unlock(t); +} + +#ifdef __KERNEL__ +static void string_convert(char *output, const char *input) +{ + if (strlen(input) > 32) { + strncpy(output, input, 32-4); + memset(output + 32-4, '.', 3); + } else + memcpy(output, input, strlen(input)); +} + +struct table_hist_record { + ktap_value key; + ktap_value val; +}; + +static int hist_record_cmp(const void *r1, const void *r2) +{ + const struct table_hist_record *i = r1; + const struct table_hist_record *j = r2; + + if ((nvalue(&i->val) == nvalue(&j->val))) { + return 0; + } else if ((nvalue(&i->val) < nvalue(&j->val))) { + return 1; + } else + return -1; +} + +static int kp_aggracc_read(ktap_aggraccval *acc); + +/* histogram: key should be number or string, value must be number */ +static void table_histdump(ktap_state *ks, ktap_table *t, int shownums) +{ + struct table_hist_record *thr; + unsigned long __maybe_unused flags; + char dist_str[40]; + int i, ratio, total = 0, count = 0, top_num, is_kernel_address = 0; + int size, num; + + size = sizeof(*thr) * (t->sizearray + sizenode(t)); + thr = kp_malloc(ks, size); + if (!thr) { + kp_error(ks, "Cannot allocate %d of histogram memory", size); + return; + } + + kp_table_lock(t); + + for (i = 0; i < t->sizearray; i++) { + ktap_value *v = &t->array[i]; + + if (isnil(v)) + continue; + + if (ttisnumber(v)) + num = nvalue(v); + else if (ttisaggracc(v)) + num = kp_aggracc_read(aggraccvalue(v)); + else { + kp_table_unlock(t); + goto error; + } + + setnvalue(&thr[count].key, i + 1); + setnvalue(&thr[count].val, num); + count++; + total += num; + } + + for (i = 0; i < sizenode(t); i++) { + ktap_tnode *n = &t->node[i]; + ktap_value *v = gval(n); + + if (isnil(gkey(n))) + continue; + + if (ttisnumber(v)) + num = nvalue(v); + else if (ttisaggracc(v)) + num = kp_aggracc_read(aggraccvalue(v)); + else { + kp_table_unlock(t); + goto error; + } + + setobj(&thr[count].key, gkey(n)); + setnvalue(&thr[count].val, num); + count++; + total += num; + } + + kp_table_unlock(t); + + sort(thr, count, sizeof(struct table_hist_record), + hist_record_cmp, NULL); + + dist_str[sizeof(dist_str) - 1] = '\0'; + + /* check the first key is a kernel text symbol or not */ + if (ttisnumber(&thr[0].key)) { + char str[KSYM_SYMBOL_LEN]; + + SPRINT_SYMBOL(str, nvalue(&thr[0].key)); + if (str[0] != '0' || str[1] != 'x') + is_kernel_address = 1; + } + + top_num = min(shownums, count); + for (i = 0; i < top_num; i++) { + ktap_value *key = &thr[i].key; + ktap_value *val = &thr[i].val; + + memset(dist_str, ' ', sizeof(dist_str) - 1); + ratio = (nvalue(val) * (sizeof(dist_str) - 1)) / total; + memset(dist_str, '@', ratio); + + if (ttisstring(key)) { + char buf[32 + 1] = {0}; + + string_convert(buf, svalue(key)); + kp_printf(ks, "%32s |%s%-7d\n", buf, dist_str, + nvalue(val)); + } else if (ttisnumber(key)) { + char str[KSYM_SYMBOL_LEN]; + char buf[32 + 1] = {0}; + + if (is_kernel_address) { + /* suppose it's a symbol, fix it in future */ + SPRINT_SYMBOL(str, nvalue(key)); + string_convert(buf, str); + kp_printf(ks, "%32s |%s%-7d\n", buf, dist_str, + nvalue(val)); + } else { + kp_printf(ks, "%32d |%s%-7d\n", nvalue(key), + dist_str, nvalue(val)); + } + } + } + + if (count > shownums) + kp_printf(ks, "%32s |\n", "..."); + + goto out; + + error: + kp_puts(ks, "error: table histogram only handle " + " (key: string/number val: number)\n"); + out: + kp_free(ks, thr); +} + +#define HISTOGRAM_DEFAULT_TOP_NUM 20 + +#define DISTRIBUTION_STR "------------- Distribution -------------" +void kp_table_histogram(ktap_state *ks, ktap_table *t) +{ + kp_printf(ks, "%32s%s%s\n", "value ", DISTRIBUTION_STR, " count"); + table_histdump(ks, t, HISTOGRAM_DEFAULT_TOP_NUM); +} + +/* + * Aggregation Table + */ + +static ktap_table *table_new2(ktap_state *ks, ktap_gcobject **list) +{ + ktap_table *t = &kp_newobject(ks, KTAP_TTABLE, sizeof(ktap_table), + list)->h; + t->flags = (u8)(~0); + t->array = NULL; + t->sizearray = 0; + t->node = (ktap_tnode *)dummynode; + t->gclist = NULL; + setnodevector(ks, t, 0); + + kp_table_lock_init(t); + return t; +} + +static int kp_aggracc_read(ktap_aggraccval *acc) +{ + switch (acc->type) { + case AGGREGATION_TYPE_COUNT: + case AGGREGATION_TYPE_MAX: + case AGGREGATION_TYPE_MIN: + case AGGREGATION_TYPE_SUM: + return acc->val; + case AGGREGATION_TYPE_AVG: + return acc->val / acc->more; + default: + return 0; + } + +} + +void kp_aggraccval_dump(ktap_state *ks, ktap_aggraccval *acc) +{ + switch (acc->type) { + case AGGREGATION_TYPE_COUNT: + case AGGREGATION_TYPE_MAX: + case AGGREGATION_TYPE_MIN: + case AGGREGATION_TYPE_SUM: + kp_printf(ks, "%d", acc->val); + break; + case AGGREGATION_TYPE_AVG: + kp_printf(ks, "%d", acc->val / acc->more); + break; + default: + break; + } +} + +static void synth_acc(ktap_aggraccval *acc1, ktap_aggraccval *acc2) +{ + switch (acc1->type) { + case AGGREGATION_TYPE_COUNT: + acc2->val += acc1->val; + break; + case AGGREGATION_TYPE_MAX: + acc2->val = max(acc1->val, acc2->val); + break; + case AGGREGATION_TYPE_MIN: + acc2->val = min(acc1->val, acc2->val); + break; + case AGGREGATION_TYPE_SUM: + acc2->val += acc1->val; + break; + case AGGREGATION_TYPE_AVG: + acc2->val += acc1->val; + acc2->more += acc1->more; + break; + default: + break; + } +} + +static ktap_aggraccval *get_accval(ktap_state *ks, int type, + ktap_gcobject **list) +{ + ktap_aggraccval *acc; + + acc = &kp_newobject(ks, KTAP_TAGGRACCVAL, sizeof(ktap_aggraccval), + list)->acc; + acc->type = type; + acc->val = 0; + acc->more = 0; + return acc; +} + +static void synth_accval(ktap_state *ks, ktap_value *o1, ktap_value *o2, + ktap_gcobject **list) +{ + ktap_aggraccval *acc; + + if (isnil(o2)) { + acc = get_accval(ks, aggraccvalue(o1)->type, list); + acc->val = aggraccvalue(o1)->val; + acc->more = aggraccvalue(o1)->more; + setaggraccvalue(o2, acc); + return; + } + + synth_acc(aggraccvalue(o1), aggraccvalue(o2)); +} + +static void move_table(ktap_state *ks, ktap_table *t1, ktap_table *t2) +{ + ktap_value *newv; + ktap_value n; + int i; + + for (i = 0; i < t1->sizearray; i++) { + ktap_value *v = &t1->array[i]; + + if (isnil(v)) + continue; + + setnvalue(&n, i); + + newv = table_set(ks, t2, &n); + synth_accval(ks, v, newv, &t2->gclist); + } + + for (i = 0; i < sizenode(t1); i++) { + ktap_tnode *node = &t1->node[i]; + + if (isnil(gkey(node))) + continue; + + newv = table_set(ks, t2, gkey(node)); + synth_accval(ks, gval(node), newv, &t2->gclist); + } +} + +ktap_table *kp_aggrtable_synthesis(ktap_state *ks, ktap_aggrtable *ah) +{ + ktap_table *synth_tbl; + int cpu; + + synth_tbl = table_new2(ks, &ah->gclist); + + for_each_possible_cpu(cpu) { + ktap_table **t = per_cpu_ptr(ah->pcpu_tbl, cpu); + move_table(ks, *t, synth_tbl); + } + + return synth_tbl; +} + +void kp_aggrtable_dump(ktap_state *ks, ktap_aggrtable *ah) +{ + kp_table_dump(ks, kp_aggrtable_synthesis(ks, ah)); +} + +ktap_aggrtable *kp_aggrtable_new(ktap_state *ks) +{ + ktap_aggrtable *ah; + int cpu; + + ah = &kp_newobject(ks, KTAP_TAGGRTABLE, sizeof(ktap_aggrtable), + NULL)->ah; + ah->pcpu_tbl = alloc_percpu(ktap_table *); + ah->gclist = NULL; + + for_each_possible_cpu(cpu) { + ktap_table **t = per_cpu_ptr(ah->pcpu_tbl, cpu); + *t = table_new2(ks, &ah->gclist); + } + + return ah; +} + +void kp_aggrtable_free(ktap_state *ks, ktap_aggrtable *ah) +{ + free_percpu(ah->pcpu_tbl); + kp_free_gclist(ks, ah->gclist); + kp_free(ks, ah); +} + +static +void handle_aggr_count(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) +{ + ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); + ktap_value *v = table_set(ks, t, key); + ktap_aggraccval *acc; + + if (isnil(v)) { + acc = get_accval(ks, AGGREGATION_TYPE_COUNT, &t->gclist); + acc->val = 1; + setaggraccvalue(v, acc); + return; + } + + acc = aggraccvalue(v); + acc->val += 1; +} + +static +void handle_aggr_max(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) +{ + ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); + ktap_value *v = table_set(ks, t, key); + ktap_aggraccval *acc; + + if (isnil(v)) { + acc = get_accval(ks, AGGREGATION_TYPE_MAX, &t->gclist); + acc->val = ks->aggr_accval; + setaggraccvalue(v, acc); + return; + } + + acc = aggraccvalue(v); + acc->val = max(acc->val, ks->aggr_accval); +} + +static +void handle_aggr_min(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) +{ + ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); + ktap_value *v = table_set(ks, t, key); + ktap_aggraccval *acc; + + if (isnil(v)) { + acc = get_accval(ks, AGGREGATION_TYPE_MIN, &t->gclist); + acc->val = ks->aggr_accval; + setaggraccvalue(v, acc); + return; + } + + acc = aggraccvalue(v); + acc->val = min(acc->val, ks->aggr_accval); +} + +static +void handle_aggr_sum(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) +{ + ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); + ktap_value *v = table_set(ks, t, key); + ktap_aggraccval *acc; + + if (isnil(v)) { + acc = get_accval(ks, AGGREGATION_TYPE_SUM, &t->gclist); + acc->val = ks->aggr_accval; + setaggraccvalue(v, acc); + return; + } + + acc = aggraccvalue(v); + acc->val += ks->aggr_accval; +} + +static +void handle_aggr_avg(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) +{ + ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); + ktap_value *v = table_set(ks, t, key); + ktap_aggraccval *acc; + + if (isnil(v)) { + acc = get_accval(ks, AGGREGATION_TYPE_AVG, &t->gclist); + acc->val = ks->aggr_accval; + acc->more = 1; + setaggraccvalue(v, acc); + return; + } + + acc = aggraccvalue(v); + acc->val += ks->aggr_accval; + acc->more++; +} + +typedef void (*aggr_func_t)(ktap_state *ks, ktap_aggrtable *ah, ktap_value *k); +static aggr_func_t kp_aggregation_handler[] = { + handle_aggr_count, + handle_aggr_max, + handle_aggr_min, + handle_aggr_sum, + handle_aggr_avg +}; + +void kp_aggrtable_set(ktap_state *ks, ktap_aggrtable *ah, + ktap_value *key, ktap_value *val) +{ + if (unlikely(!ttisaggrval(val))) { + kp_error(ks, "set invalid value to aggregation table\n"); + return; + } + + kp_aggregation_handler[nvalue(val)](ks, ah, key); +} + + +void kp_aggrtable_get(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key, + ktap_value *val) +{ + ktap_aggraccval acc; /* in stack */ + const ktap_value *v; + int cpu; + + acc.val = -1; + acc.more = -1; + + for_each_possible_cpu(cpu) { + ktap_table **t = per_cpu_ptr(ah->pcpu_tbl, cpu); + + v = table_get(*t, key); + if (isnil(v)) + continue; + + if (acc.more == -1) { + acc = *aggraccvalue(v); + continue; + } + + synth_acc(aggraccvalue(v), &acc); + } + + if (acc.more == -1) { + setnilvalue(val); + } else { + setnvalue(val, kp_aggracc_read(&acc)); + } +} + +void kp_aggrtable_histogram(ktap_state *ks, ktap_aggrtable *ah) +{ + kp_table_histogram(ks, kp_aggrtable_synthesis(ks, ah)); +} +#endif diff --git a/drivers/staging/ktap/interpreter/transport.c b/drivers/staging/ktap/interpreter/transport.c new file mode 100644 index 000000000000..4cd3662b792a --- /dev/null +++ b/drivers/staging/ktap/interpreter/transport.c @@ -0,0 +1,636 @@ +/* + * transport.c - ktap transport functionality + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/debugfs.h> +#include <linux/ftrace_event.h> +#include <linux/stacktrace.h> +#include <linux/clocksource.h> +#include <asm/uaccess.h> +#include "../include/ktap.h" + +struct ktap_trace_iterator { + struct ring_buffer *buffer; + int print_timestamp; + void *private; + + struct trace_iterator iter; +}; + +enum ktap_trace_type { + __TRACE_FIRST_TYPE = 0, + + TRACE_FN = 1, /* must be same as ftrace definition in kernel */ + TRACE_PRINT, + TRACE_BPUTS, + TRACE_STACK, + TRACE_USER_STACK, + + __TRACE_LAST_TYPE, +}; + +#define KTAP_TRACE_ITER(iter) \ + container_of(iter, struct ktap_trace_iterator, iter) + +ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) +{ + int len; + int ret; + + if (!cnt) + return 0; + + if (s->len <= s->readpos) + return -EBUSY; + + len = s->len - s->readpos; + if (cnt > len) + cnt = len; + ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); + if (ret == cnt) + return -EFAULT; + + cnt -= ret; + + s->readpos += cnt; + return cnt; +} + +int trace_seq_puts(struct trace_seq *s, const char *str) +{ + int len = strlen(str); + + if (s->full) + return 0; + + if (len > ((PAGE_SIZE - 1) - s->len)) { + s->full = 1; + return 0; + } + + memcpy(s->buffer + s->len, str, len); + s->len += len; + + return len; +} + +static int trace_empty(struct trace_iterator *iter) +{ + struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); + int cpu; + + for_each_online_cpu(cpu) { + if (!ring_buffer_empty_cpu(ktap_iter->buffer, cpu)) + return 0; + } + + return 1; +} + +static void trace_consume(struct trace_iterator *iter) +{ + struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); + + ring_buffer_consume(ktap_iter->buffer, iter->cpu, &iter->ts, + &iter->lost_events); +} + +unsigned long long ns2usecs(cycle_t nsec) +{ + nsec += 500; + do_div(nsec, 1000); + return nsec; +} + +static int trace_print_timestamp(struct trace_iterator *iter) +{ + struct trace_seq *s = &iter->seq; + unsigned long long t; + unsigned long secs, usec_rem; + + t = ns2usecs(iter->ts); + usec_rem = do_div(t, USEC_PER_SEC); + secs = (unsigned long)t; + + return trace_seq_printf(s, "%5lu.%06lu: ", secs, usec_rem); +} + +/* todo: export kernel function ftrace_find_event in future, and make faster */ +static struct trace_event *(*ftrace_find_event)(int type); + +static enum print_line_t print_trace_fmt(struct trace_iterator *iter) +{ + struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); + struct trace_entry *entry = iter->ent; + struct trace_event *ev; + + ev = ftrace_find_event(entry->type); + + if (ktap_iter->print_timestamp && !trace_print_timestamp(iter)) + return TRACE_TYPE_PARTIAL_LINE; + + if (ev) { + int ret = ev->funcs->trace(iter, 0, ev); + + /* overwrite '\n' at the ending */ + iter->seq.buffer[iter->seq.len - 1] = '\0'; + iter->seq.len--; + return ret; + } + + return TRACE_TYPE_PARTIAL_LINE; +} + +static enum print_line_t print_trace_stack(struct trace_iterator *iter) +{ + struct trace_entry *entry = iter->ent; + struct stack_trace trace; + char str[KSYM_SYMBOL_LEN]; + int i; + + trace.entries = (unsigned long *)(entry + 1); + trace.nr_entries = (iter->ent_size - sizeof(*entry)) / + sizeof(unsigned long); + + if (!trace_seq_puts(&iter->seq, "<stack trace>\n")) + return TRACE_TYPE_PARTIAL_LINE; + + for (i = 0; i < trace.nr_entries; i++) { + unsigned long p = trace.entries[i]; + + if (p == ULONG_MAX) + break; + + sprint_symbol(str, p); + if (!trace_seq_printf(&iter->seq, " => %s\n", str)) + return TRACE_TYPE_PARTIAL_LINE; + } + + return TRACE_TYPE_HANDLED; +} + +struct ktap_ftrace_entry { + struct trace_entry entry; + unsigned long ip; + unsigned long parent_ip; +}; + +static enum print_line_t print_trace_fn(struct trace_iterator *iter) +{ + struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); + struct ktap_ftrace_entry *field = (struct ktap_ftrace_entry *)iter->ent; + char str[KSYM_SYMBOL_LEN]; + + if (ktap_iter->print_timestamp && !trace_print_timestamp(iter)) + return TRACE_TYPE_PARTIAL_LINE; + + sprint_symbol(str, field->ip); + if (!trace_seq_puts(&iter->seq, str)) + return TRACE_TYPE_PARTIAL_LINE; + + if (!trace_seq_puts(&iter->seq, " <- ")) + return TRACE_TYPE_PARTIAL_LINE; + + sprint_symbol(str, field->parent_ip); + if (!trace_seq_puts(&iter->seq, str)) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t print_trace_bputs(struct trace_iterator *iter) +{ + if (!trace_seq_puts(&iter->seq, + (const char *)(*(unsigned long *)(iter->ent + 1)))) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t print_trace_line(struct trace_iterator *iter) +{ + struct trace_entry *entry = iter->ent; + char *str = (char *)(entry + 1); + + if (entry->type == TRACE_PRINT) { + if (!trace_seq_printf(&iter->seq, "%s", str)) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; + } + + if (entry->type == TRACE_BPUTS) + return print_trace_bputs(iter); + + if (entry->type == TRACE_STACK) + return print_trace_stack(iter); + + if (entry->type == TRACE_FN) + return print_trace_fn(iter); + + return print_trace_fmt(iter); +} + +static struct trace_entry * +peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts, + unsigned long *lost_events) +{ + struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); + struct ring_buffer_event *event; + + event = ring_buffer_peek(ktap_iter->buffer, cpu, ts, lost_events); + if (event) { + iter->ent_size = ring_buffer_event_length(event); + return ring_buffer_event_data(event); + } + + return NULL; +} + +static struct trace_entry * +__find_next_entry(struct trace_iterator *iter, int *ent_cpu, + unsigned long *missing_events, u64 *ent_ts) +{ + struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); + struct ring_buffer *buffer = ktap_iter->buffer; + struct trace_entry *ent, *next = NULL; + unsigned long lost_events = 0, next_lost = 0; + u64 next_ts = 0, ts; + int next_cpu = -1; + int next_size = 0; + int cpu; + + for_each_online_cpu(cpu) { + if (ring_buffer_empty_cpu(buffer, cpu)) + continue; + + ent = peek_next_entry(iter, cpu, &ts, &lost_events); + /* + * Pick the entry with the smallest timestamp: + */ + if (ent && (!next || ts < next_ts)) { + next = ent; + next_cpu = cpu; + next_ts = ts; + next_lost = lost_events; + next_size = iter->ent_size; + } + } + + iter->ent_size = next_size; + + if (ent_cpu) + *ent_cpu = next_cpu; + + if (ent_ts) + *ent_ts = next_ts; + + if (missing_events) + *missing_events = next_lost; + + return next; +} + +/* Find the next real entry, and increment the iterator to the next entry */ +static void *trace_find_next_entry_inc(struct trace_iterator *iter) +{ + iter->ent = __find_next_entry(iter, &iter->cpu, + &iter->lost_events, &iter->ts); + if (iter->ent) + iter->idx++; + + return iter->ent ? iter : NULL; +} + +static void poll_wait_pipe(void) +{ + set_current_state(TASK_INTERRUPTIBLE); + /* sleep for 100 msecs, and try again. */ + schedule_timeout(HZ / 10); +} + +static int tracing_wait_pipe(struct file *filp) +{ + struct trace_iterator *iter = filp->private_data; + struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); + ktap_state *ks = ktap_iter->private; + + while (trace_empty(iter)) { + + if ((filp->f_flags & O_NONBLOCK)) { + return -EAGAIN; + } + + mutex_unlock(&iter->mutex); + + poll_wait_pipe(); + + mutex_lock(&iter->mutex); + + if (G(ks)->wait_user && trace_empty(iter)) + return -EINTR; + } + + return 1; +} + +static ssize_t +tracing_read_pipe(struct file *filp, char __user *ubuf, size_t cnt, + loff_t *ppos) +{ + struct trace_iterator *iter = filp->private_data; + ssize_t sret; + + /* return any leftover data */ + sret = trace_seq_to_user(&iter->seq, ubuf, cnt); + if (sret != -EBUSY) + return sret; + /* + * Avoid more than one consumer on a single file descriptor + * This is just a matter of traces coherency, the ring buffer itself + * is protected. + */ + mutex_lock(&iter->mutex); + +waitagain: + sret = tracing_wait_pipe(filp); + if (sret <= 0) + goto out; + + /* stop when tracing is finished */ + if (trace_empty(iter)) { + sret = 0; + goto out; + } + + if (cnt >= PAGE_SIZE) + cnt = PAGE_SIZE - 1; + + /* reset all but tr, trace, and overruns */ + memset(&iter->seq, 0, + sizeof(struct trace_iterator) - + offsetof(struct trace_iterator, seq)); + iter->pos = -1; + + while (trace_find_next_entry_inc(iter) != NULL) { + enum print_line_t ret; + int len = iter->seq.len; + + ret = print_trace_line(iter); + if (ret == TRACE_TYPE_PARTIAL_LINE) { + /* don't print partial lines */ + iter->seq.len = len; + break; + } + if (ret != TRACE_TYPE_NO_CONSUME) + trace_consume(iter); + + if (iter->seq.len >= cnt) + break; + + /* + * Setting the full flag means we reached the trace_seq buffer + * size and we should leave by partial output condition above. + * One of the trace_seq_* functions is not used properly. + */ + WARN_ONCE(iter->seq.full, "full flag set for trace type %d", + iter->ent->type); + } + + /* Now copy what we have to the user */ + sret = trace_seq_to_user(&iter->seq, ubuf, cnt); + if (iter->seq.readpos >= iter->seq.len) + trace_seq_init(&iter->seq); + + /* + * If there was nothing to send to user, in spite of consuming trace + * entries, go back to wait for more entries. + */ + if (sret == -EBUSY) + goto waitagain; + +out: + mutex_unlock(&iter->mutex); + + return sret; +} + +static int tracing_open_pipe(struct inode *inode, struct file *filp) +{ + struct ktap_trace_iterator *ktap_iter; + ktap_state *ks = inode->i_private; + + /* create a buffer to store the information to pass to userspace */ + ktap_iter = kzalloc(sizeof(*ktap_iter), GFP_KERNEL); + if (!ktap_iter) + return -ENOMEM; + + ktap_iter->private = ks; + ktap_iter->buffer = G(ks)->buffer; + ktap_iter->print_timestamp = G(ks)->parm->print_timestamp; + mutex_init(&ktap_iter->iter.mutex); + filp->private_data = &ktap_iter->iter; + + nonseekable_open(inode, filp); + + return 0; +} + +static int tracing_release_pipe(struct inode *inode, struct file *file) +{ + struct trace_iterator *iter = file->private_data; + struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); + + mutex_destroy(&iter->mutex); + kfree(ktap_iter); + return 0; +} + +static const struct file_operations tracing_pipe_fops = { + .open = tracing_open_pipe, + .read = tracing_read_pipe, + .splice_read = NULL, + .release = tracing_release_pipe, + .llseek = no_llseek, +}; + +/* + * print_backtrace maybe called from ktap mainthread, so be + * care on race with event closure thread. + * + * preempt disabled in ring_buffer_lock_reserve + * + * The implementation is similar with funtion __ftrace_trace_stack. + */ +void kp_transport_print_backtrace(ktap_state *ks) +{ + struct ring_buffer *buffer = G(ks)->buffer; + struct ring_buffer_event *event; + struct trace_entry *entry; + int size; + + size = KTAP_STACK_MAX_ENTRIES * sizeof(unsigned long); + event = ring_buffer_lock_reserve(buffer, sizeof(*entry) + size); + if (!event) { + return; + } else { + struct stack_trace trace; + + entry = ring_buffer_event_data(event); + tracing_generic_entry_update(entry, 0, 0); + entry->type = TRACE_STACK; + + trace.nr_entries = 0; + trace.skip = 10; + trace.max_entries = KTAP_STACK_MAX_ENTRIES; + trace.entries = (unsigned long *)(entry + 1); + save_stack_trace(&trace); + + ring_buffer_unlock_commit(buffer, event); + } + + return; +} + +void kp_transport_event_write(ktap_state *ks, struct ktap_event *e) +{ + struct ring_buffer *buffer = G(ks)->buffer; + struct ring_buffer_event *event; + struct trace_entry *entry; + + event = ring_buffer_lock_reserve(buffer, e->entry_size + + sizeof(struct ftrace_event_call *)); + if (!event) { + return; + } else { + entry = ring_buffer_event_data(event); + + memcpy(entry, e->entry, e->entry_size); + + ring_buffer_unlock_commit(buffer, event); + } +} + +void kp_transport_write(ktap_state *ks, const void *data, size_t length) +{ + struct ring_buffer *buffer = G(ks)->buffer; + struct ring_buffer_event *event; + struct trace_entry *entry; + int size; + + size = sizeof(struct trace_entry) + length; + + event = ring_buffer_lock_reserve(buffer, size); + if (!event) { + return; + } else { + entry = ring_buffer_event_data(event); + + tracing_generic_entry_update(entry, 0, 0); + entry->type = TRACE_PRINT; + memcpy(entry + 1, data, length); + + ring_buffer_unlock_commit(buffer, event); + } +} + +/* general print function */ +void kp_printf(ktap_state *ks, const char *fmt, ...) +{ + char buff[1024]; + va_list args; + int len; + + va_start(args, fmt); + len = vscnprintf(buff, 1024, fmt, args); + va_end(args); + + buff[len] = '\0'; + kp_transport_write(ks, buff, len + 1); +} + +void __kp_puts(ktap_state *ks, const char *str) +{ + kp_transport_write(ks, str, strlen(str) + 1); +} + +void __kp_bputs(ktap_state *ks, const char *str) +{ + struct ring_buffer *buffer = G(ks)->buffer; + struct ring_buffer_event *event; + struct trace_entry *entry; + int size; + + size = sizeof(struct trace_entry) + sizeof(unsigned long *); + + event = ring_buffer_lock_reserve(buffer, size); + if (!event) { + return; + } else { + entry = ring_buffer_event_data(event); + + tracing_generic_entry_update(entry, 0, 0); + entry->type = TRACE_BPUTS; + *(unsigned long *)(entry + 1) = (unsigned long)str; + + ring_buffer_unlock_commit(buffer, event); + } +} + +void kp_transport_exit(ktap_state *ks) +{ + ring_buffer_free(G(ks)->buffer); + debugfs_remove(G(ks)->trace_pipe_dentry); +} + +#define TRACE_BUF_SIZE_DEFAULT 1441792UL /* 16384 * 88 (sizeof(entry)) */ + +int kp_transport_init(ktap_state *ks, struct dentry *dir) +{ + struct ring_buffer *buffer; + struct dentry *dentry; + char filename[32] = {0}; + + ftrace_find_event = (void *)kallsyms_lookup_name("ftrace_find_event"); + if (!ftrace_find_event) { + printk("ktap: cannot lookup ftrace_find_event in kallsyms\n"); + return -EINVAL; + } + + buffer = ring_buffer_alloc(TRACE_BUF_SIZE_DEFAULT, RB_FL_OVERWRITE); + if (!buffer) + return -ENOMEM; + + sprintf(filename, "trace_pipe_%d", (int)task_tgid_vnr(current)); + + dentry = debugfs_create_file(filename, 0444, dir, + ks, &tracing_pipe_fops); + if (!dentry) { + pr_err("ktapvm: cannot create trace_pipe file in debugfs\n"); + ring_buffer_free(buffer); + return -1; + } + + G(ks)->buffer = buffer; + G(ks)->trace_pipe_dentry = dentry; + + return 0; +} + diff --git a/drivers/staging/ktap/interpreter/tstring.c b/drivers/staging/ktap/interpreter/tstring.c new file mode 100644 index 000000000000..ce4c88df2cc8 --- /dev/null +++ b/drivers/staging/ktap/interpreter/tstring.c @@ -0,0 +1,287 @@ +/* + * tstring.c - ktap tstring data struction manipulation function + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef __KERNEL__ +#include "../include/ktap.h" +#else +#include "../include/ktap_types.h" +#endif + +#define STRING_MAXSHORTLEN 40 + +int kp_tstring_cmp(const ktap_string *ls, const ktap_string *rs) +{ + const char *l = getstr(ls); + size_t ll = ls->tsv.len; + const char *r = getstr(rs); + size_t lr = rs->tsv.len; + + for (;;) { + int temp = strcmp(l, r); + if (temp != 0) + return temp; + else { + /* strings are equal up to a `\0' */ + + /* index of first `\0' in both strings */ + size_t len = strlen(l); + + /* r is finished? */ + if (len == lr) + return (len == ll) ? 0 : 1; + else if (len == ll) /* l is finished? */ + return -1; + + /* + * both strings longer than `len'; + * go on comparing (after the `\0') + */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } +} + +/* + * equality for long strings + */ +int kp_tstring_eqlngstr(ktap_string *a, ktap_string *b) +{ + size_t len = a->tsv.len; + + return (a == b) || ((len == b->tsv.len) && + (memcmp(getstr(a), getstr(b), len) == 0)); +} + +/* + * equality for strings + */ +int kp_tstring_eqstr(ktap_string *a, ktap_string *b) +{ + return (a->tsv.tt == b->tsv.tt) && + (a->tsv.tt == KTAP_TSHRSTR ? eqshrstr(a, b) : + kp_tstring_eqlngstr(a, b)); +} + +#define STRING_HASHLIMIT 5 +unsigned int kp_string_hash(const char *str, size_t l, unsigned int seed) +{ + unsigned int h = seed ^ l; + size_t l1; + size_t step = (l >> STRING_HASHLIMIT) + 1; + + for (l1 = l; l1 >= step; l1 -= step) + h = h ^ ((h<<5) + (h>>2) + (u8)(str[l1 - 1])); + + return h; +} + + +/* + * resizes the string table + */ +void kp_tstring_resize(ktap_state *ks, int newsize) +{ + int i; + ktap_stringtable *tb = &G(ks)->strt; + + if (newsize > tb->size) { + kp_realloc(ks, tb->hash, tb->size, newsize, ktap_gcobject *); + + for (i = tb->size; i < newsize; i++) + tb->hash[i] = NULL; + } + + /* rehash */ + for (i = 0; i < tb->size; i++) { + ktap_gcobject *p = tb->hash[i]; + tb->hash[i] = NULL; + + while (p) { + ktap_gcobject *next = gch(p)->next; + unsigned int h = lmod(gco2ts(p)->hash, newsize); + + gch(p)->next = tb->hash[h]; + tb->hash[h] = p; + p = next; + } + } + + if (newsize < tb->size) { + /* shrinking slice must be empty */ + kp_realloc(ks, tb->hash, tb->size, newsize, ktap_gcobject *); + } + + tb->size = newsize; +} + +/* + * creates a new string object + */ +static ktap_string *createstrobj(ktap_state *ks, const char *str, size_t l, + int tag, unsigned int h, ktap_gcobject **list) +{ + ktap_string *ts; + size_t totalsize; /* total size of TString object */ + + totalsize = sizeof(ktap_string) + ((l + 1) * sizeof(char)); + ts = &kp_newobject(ks, tag, totalsize, list)->ts; + ts->tsv.len = l; + ts->tsv.hash = h; + ts->tsv.extra = 0; + memcpy(ts + 1, str, l * sizeof(char)); + ((char *)(ts + 1))[l] = '\0'; /* ending 0 */ + return ts; +} + +/* + * creates a new short string, inserting it into string table + */ +static ktap_string *newshrstr(ktap_state *ks, const char *str, size_t l, + unsigned int h) +{ + ktap_gcobject **list; + ktap_stringtable *tb = &G(ks)->strt; + ktap_string *s; + + if (tb->nuse >= (int)tb->size) + kp_tstring_resize(ks, tb->size * 2); /* too crowded */ + + list = &tb->hash[lmod(h, tb->size)]; + s = createstrobj(ks, str, l, KTAP_TSHRSTR, h, list); + tb->nuse++; + return s; +} + +#ifdef __KERNEL__ +static arch_spinlock_t tstring_lock = + (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; +#endif + +/* + * checks whether short string exists and reuses it or creates a new one + */ +static ktap_string *internshrstr(ktap_state *ks, const char *str, size_t l) +{ + ktap_gcobject *o; + ktap_global_state *g = G(ks); + ktap_string *ts; + unsigned int h = kp_string_hash(str, l, g->seed); + unsigned long __maybe_unused flags; + +#ifdef __KERNEL__ + local_irq_save(flags); + arch_spin_lock(&tstring_lock); +#endif + + for (o = g->strt.hash[lmod(h, g->strt.size)]; o != NULL; + o = gch(o)->next) { + ts = rawgco2ts(o); + + if (h == ts->tsv.hash && ts->tsv.len == l && + (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) + goto out; + } + + ts = newshrstr(ks, str, l, h); /* not found; create a new string */ + + out: +#ifdef __KERNEL__ + arch_spin_unlock(&tstring_lock); + local_irq_restore(flags); +#endif + return ts; +} + + +/* + * new string (with explicit length) + */ +ktap_string *kp_tstring_newlstr(ktap_state *ks, const char *str, size_t l) +{ + /* short string? */ + if (l <= STRING_MAXSHORTLEN) + return internshrstr(ks, str, l); + else + return createstrobj(ks, str, l, KTAP_TLNGSTR, G(ks)->seed, + NULL); +} + +ktap_string *kp_tstring_newlstr_local(ktap_state *ks, const char *str, size_t l) +{ + return createstrobj(ks, str, l, KTAP_TLNGSTR, G(ks)->seed, + &ks->gclist); +} + +/* + * new zero-terminated string + */ +ktap_string *kp_tstring_new(ktap_state *ks, const char *str) +{ + return kp_tstring_newlstr(ks, str, strlen(str)); +} + +ktap_string *kp_tstring_new_local(ktap_state *ks, const char *str) +{ + return createstrobj(ks, str, strlen(str), KTAP_TLNGSTR, G(ks)->seed, + &ks->gclist); +} + +void kp_tstring_freeall(ktap_state *ks) +{ + ktap_global_state *g = G(ks); + int h; + + for (h = 0; h < g->strt.size; h++) { + ktap_gcobject *o, *next; + o = g->strt.hash[h]; + while (o) { + next = gch(o)->next; + kp_free(ks, o); + o = next; + } + g->strt.hash[h] = NULL; + } + + kp_free(ks, g->strt.hash); +} + +/* todo: dump long string, strt table only contain short string */ +void kp_tstring_dump(ktap_state *ks) +{ + ktap_gcobject *o; + ktap_global_state *g = G(ks); + int h; + + kp_printf(ks, "tstring dump: strt size: %d, nuse: %d\n", g->strt.size, + g->strt.nuse); + for (h = 0; h < g->strt.size; h++) { + for (o = g->strt.hash[h]; o != NULL; o = gch(o)->next) { + ktap_string *ts = rawgco2ts(o); + kp_printf(ks, "%s [%d]\n", getstr(ts), (int)ts->tsv.len); + } + } +} + diff --git a/drivers/staging/ktap/interpreter/vm.c b/drivers/staging/ktap/interpreter/vm.c new file mode 100644 index 000000000000..bc7b9518a88f --- /dev/null +++ b/drivers/staging/ktap/interpreter/vm.c @@ -0,0 +1,1369 @@ +/* + * vm.c - ktap script virtual machine in Linux kernel + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/slab.h> +#include <linux/ftrace_event.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include "../include/ktap.h" + +#define KTAP_MINSTACK 20 + +/* todo: enlarge maxstack for big system like 64-bit */ +#define KTAP_MAXSTACK 15000 + +#define KTAP_STACK_SIZE (BASIC_STACK_SIZE * sizeof(ktap_value)) + +#define CIST_KTAP (1 << 0) /* call is running a ktap function */ +#define CIST_REENTRY (1 << 2) + +#define isktapfunc(ci) ((ci)->callstatus & CIST_KTAP) + +static void ktap_concat(ktap_state *ks, int start, int end) +{ + int i, len = 0; + StkId top = ks->ci->u.l.base; + ktap_string *ts; + char *ptr, *buffer; + + for (i = start; i <= end; i++) { + if (!ttisstring(top + i)) { + kp_error(ks, "cannot concat non-string\n"); + setnilvalue(top + start); + return; + } + + len += rawtsvalue(top + i)->tsv.len; + } + + if (len >= KTAP_PERCPU_BUFFER_SIZE) { + kp_error(ks, "Error: too long string concatenation\n"); + return; + } + + preempt_disable_notrace(); + + buffer = kp_percpu_data(KTAP_PERCPU_DATA_BUFFER); + ptr = buffer; + + for (i = start; i <= end; i++) { + int len = rawtsvalue(top + i)->tsv.len; + strncpy(ptr, svalue(top + i), len); + ptr += len; + } + ts = kp_tstring_newlstr(ks, buffer, len); + setsvalue(top + start, ts); + + preempt_enable_notrace(); +} + +/* todo: compare l == r if both is tstring type? */ +static int lessthan(ktap_state *ks, const ktap_value *l, const ktap_value *r) +{ + if (ttisnumber(l) && ttisnumber(r)) + return NUMLT(nvalue(l), nvalue(r)); + else if (ttisstring(l) && ttisstring(r)) + return kp_tstring_cmp(rawtsvalue(l), rawtsvalue(r)) < 0; + + return 0; +} + +static int lessequal(ktap_state *ks, const ktap_value *l, const ktap_value *r) +{ + if (ttisnumber(l) && ttisnumber(r)) + return NUMLE(nvalue(l), nvalue(r)); + else if (ttisstring(l) && ttisstring(r)) + return kp_tstring_cmp(rawtsvalue(l), rawtsvalue(r)) <= 0; + + return 0; +} + +static int fb2int (int x) +{ + int e = (x >> 3) & 0x1f; + if (e == 0) + return x; + else + return ((x & 7) + 8) << (e - 1); +} + +static const ktap_value *ktap_tonumber(const ktap_value *obj, ktap_value *n) +{ + if (ttisnumber(obj)) + return obj; + + return NULL; +} + +static ktap_upval *findupval(ktap_state *ks, StkId level) +{ + ktap_global_state *g = G(ks); + ktap_gcobject **pp = &ks->openupval; + ktap_upval *p; + ktap_upval *uv; + + while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { + if (p->v == level) { /* found a corresponding upvalue? */ + return p; + } + pp = &p->next; + } + + /* not found: create a new one */ + uv = &kp_newobject(ks, KTAP_TUPVAL, sizeof(ktap_upval), pp)->uv; + uv->v = level; /* current value lives in the stack */ + uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ + uv->u.l.next = g->uvhead.u.l.next; + uv->u.l.next->u.l.prev = uv; + g->uvhead.u.l.next = uv; + return uv; +} + +/* todo: implement this*/ +static void function_close (ktap_state *ks, StkId level) +{ +} + +/* create a new closure */ +static void pushclosure(ktap_state *ks, ktap_proto *p, ktap_upval **encup, + StkId base, StkId ra) +{ + int nup = p->sizeupvalues; + ktap_upvaldesc *uv = p->upvalues; + int i; + ktap_closure *ncl = kp_newlclosure(ks, nup); + + ncl->l.p = p; + setcllvalue(ra, ncl); /* anchor new closure in stack */ + + /* fill in its upvalues */ + for (i = 0; i < nup; i++) { + if (uv[i].instack) { + /* upvalue refers to local variable? */ + ncl->l.upvals[i] = findupval(ks, base + uv[i].idx); + } else { + /* get upvalue from enclosing function */ + ncl->l.upvals[i] = encup[uv[i].idx]; + } + } + //p->cache = ncl; /* save it on cache for reuse */ +} + +static void gettable(ktap_state *ks, const ktap_value *t, ktap_value *key, + StkId val) +{ + if (ttistable(t)) { + setobj(val, kp_table_get(hvalue(t), key)); + } else if (ttisaggrtable(t)) { + kp_aggrtable_get(ks, ahvalue(t), key, val); + } else { + kp_error(ks, "get key from non-table\n"); + } +} + +static void settable(ktap_state *ks, const ktap_value *t, ktap_value *key, + StkId val) +{ + if (ttistable(t)) { + kp_table_setvalue(ks, hvalue(t), key, val); + } else if (ttisaggrtable(t)) { + kp_aggrtable_set(ks, ahvalue(t), key, val); + } else { + kp_error(ks, "set key to non-table\n"); + } +} + +static void settable_incr(ktap_state *ks, const ktap_value *t, ktap_value *key, + StkId val) +{ + if (unlikely(!ttistable(t))) { + kp_error(ks, "use += operator for non-table\n"); + return; + } + + if (unlikely(!ttisnumber(val))) { + kp_error(ks, "use non-number to += operator\n"); + return; + } + + kp_table_atomic_inc(ks, hvalue(t), key, nvalue(val)); +} + + +static void growstack(ktap_state *ks, int n) +{ + ktap_value *oldstack; + int lim; + ktap_callinfo *ci; + ktap_gcobject *up; + int size = ks->stacksize; + int needed = (int)(ks->top - ks->stack) + n; + int newsize = 2 * size; + + if (newsize > KTAP_MAXSTACK) + newsize = KTAP_MAXSTACK; + + if (newsize < needed) + newsize = needed; + + if (newsize > KTAP_MAXSTACK) { /* stack overflow? */ + kp_error(ks, "stack overflow\n"); + return; + } + + /* realloc stack */ + oldstack = ks->stack; + lim = ks->stacksize; + kp_realloc(ks, ks->stack, ks->stacksize, newsize, ktap_value); + + for (; lim < newsize; lim++) + setnilvalue(ks->stack + lim); + ks->stacksize = newsize; + ks->stack_last = ks->stack + newsize; + + /* correct stack */ + ks->top = (ks->top - oldstack) + ks->stack; + for (up = ks->openupval; up != NULL; up = up->gch.next) + gco2uv(up)->v = (gco2uv(up)->v - oldstack) + ks->stack; + + for (ci = ks->ci; ci != NULL; ci = ci->prev) { + ci->top = (ci->top - oldstack) + ks->stack; + ci->func = (ci->func - oldstack) + ks->stack; + if (isktapfunc(ci)) + ci->u.l.base = (ci->u.l.base - oldstack) + ks->stack; + } + +} + +static inline void checkstack(ktap_state *ks, int n) +{ + if (ks->stack_last - ks->top <= n) + growstack(ks, n); +} + +static StkId adjust_varargs(ktap_state *ks, ktap_proto *p, int actual) +{ + int i; + int nfixargs = p->numparams; + StkId base, fixed; + + /* move fixed parameters to final position */ + fixed = ks->top - actual; /* first fixed argument */ + base = ks->top; /* final position of first argument */ + + for (i=0; i < nfixargs; i++) { + setobj(ks->top++, fixed + i); + setnilvalue(fixed + i); + } + + return base; +} + +static int poscall(ktap_state *ks, StkId first_result) +{ + ktap_callinfo *ci; + StkId res; + int wanted, i; + + ci = ks->ci; + + res = ci->func; + wanted = ci->nresults; + + ks->ci = ci = ci->prev; + + for (i = wanted; i != 0 && first_result < ks->top; i--) + setobj(res++, first_result++); + + while(i-- > 0) + setnilvalue(res++); + + ks->top = res; + + return (wanted - (-1)); +} + +static ktap_callinfo *extend_ci(ktap_state *ks) +{ + ktap_callinfo *ci; + + ci = kp_malloc(ks, sizeof(ktap_callinfo)); + ks->ci->next = ci; + ci->prev = ks->ci; + ci->next = NULL; + + return ci; +} + +static void free_ci(ktap_state *ks) +{ + ktap_callinfo *ci = ks->ci; + ktap_callinfo *next; + + if (!ci) + return; + + next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) { + next = ci->next; + kp_free(ks, ci); + } +} + +#define next_ci(ks) (ks->ci = ks->ci->next ? ks->ci->next : extend_ci(ks)) +#define savestack(ks, p) ((char *)(p) - (char *)ks->stack) +#define restorestack(ks, n) ((ktap_value *)((char *)ks->stack + (n))) + +static int precall(ktap_state *ks, StkId func, int nresults) +{ + ktap_cfunction f; + ktap_callinfo *ci; + ktap_proto *p; + StkId base; + ptrdiff_t funcr = savestack(ks, func); + int n; + + switch (ttype(func)) { + case KTAP_TLCF: /* light C function */ + f = fvalue(func); + goto CFUNC; + case KTAP_TCCL: /* C closure */ + f = clcvalue(func)->f; + CFUNC: + checkstack(ks, KTAP_MINSTACK); + ci = next_ci(ks); + ci->nresults = nresults; + ci->func = restorestack(ks, funcr); + ci->top = ks->top + KTAP_MINSTACK; + ci->callstatus = 0; + n = (*f)(ks); + poscall(ks, ks->top - n); + return 1; + case KTAP_TLCL: + p = CLVALUE(func)->p; + checkstack(ks, p->maxstacksize); + func = restorestack(ks, funcr); + n = (int)(ks->top - func) - 1; /* number of real arguments */ + + /* complete missing arguments */ + for (; n < p->numparams; n++) + setnilvalue(ks->top++); + + base = (!p->is_vararg) ? func + 1 : adjust_varargs(ks, p, n); + ci = next_ci(ks); + ci->nresults = nresults; + ci->func = func; + ci->u.l.base = base; + ci->top = base + p->maxstacksize; + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = CIST_KTAP; + ks->top = ci->top; + return 0; + default: + kp_error(ks, "attempt to call nil function\n"); + } + + return 0; +} + +#define RA(i) (base+GETARG_A(i)) +#define RB(i) (base+GETARG_B(i)) +#define ISK(x) ((x) & BITRK) +#define RC(i) base+GETARG_C(i) +#define RKB(i) \ + ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i) +#define RKC(i) \ + ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i) + +#define dojump(ci,i,e) { \ + ci->u.l.savedpc += GETARG_sBx(i) + e; } +#define donextjump(ci) { instr = *ci->u.l.savedpc; dojump(ci, instr, 1); } + +#define arith_op(ks, op) { \ + ktap_value *rb = RKB(instr); \ + ktap_value *rc = RKC(instr); \ + if (ttisnumber(rb) && ttisnumber(rc)) { \ + ktap_number nb = nvalue(rb), nc = nvalue(rc); \ + setnvalue(ra, op(nb, nc)); \ + } else { \ + kp_puts(ks, "Error: Cannot make arith operation\n"); \ + return; \ + } } + +static ktap_value *cfunction_cache_get(ktap_state *ks, int index); + +static void ktap_execute(ktap_state *ks) +{ + int exec_count = 0; + ktap_callinfo *ci; + ktap_lclosure *cl; + ktap_value *k; + unsigned int instr, opcode; + StkId base; /* stack pointer */ + StkId ra; /* register pointer */ + int res, nresults; /* temp varible */ + + ci = ks->ci; + + newframe: + cl = CLVALUE(ci->func); + k = cl->p->k; + base = ci->u.l.base; + + mainloop: + /* main loop of interpreter */ + + /* dead loop detaction */ + if (exec_count++ == kp_max_exec_count) { + if (G(ks)->mainthread != ks) { + kp_error(ks, "non-mainthread executed instructions " + "exceed max limit(%d)\n", + kp_max_exec_count); + return; + } + + cond_resched(); + if (signal_pending(current)) { + flush_signals(current); + return; + } + exec_count = 0; + } + + instr = *(ci->u.l.savedpc++); + opcode = GET_OPCODE(instr); + + /* ra is target register */ + ra = RA(instr); + + switch (opcode) { + case OP_MOVE: + setobj(ra, base + GETARG_B(instr)); + break; + case OP_LOADK: + setobj(ra, k + GETARG_Bx(instr)); + break; + case OP_LOADKX: + setobj(ra, k + GETARG_Ax(*ci->u.l.savedpc++)); + break; + case OP_LOADBOOL: + setbvalue(ra, GETARG_B(instr)); + if (GETARG_C(instr)) + ci->u.l.savedpc++; + break; + case OP_LOADNIL: { + int b = GETARG_B(instr); + do { + setnilvalue(ra++); + } while (b--); + break; + } + case OP_GETUPVAL: { + int b = GETARG_B(instr); + setobj(ra, cl->upvals[b]->v); + break; + } + case OP_GETTABUP: { + int b = GETARG_B(instr); + gettable(ks, cl->upvals[b]->v, RKC(instr), ra); + base = ci->u.l.base; + break; + } + case OP_GETTABLE: + gettable(ks, RB(instr), RKC(instr), ra); + base = ci->u.l.base; + break; + case OP_SETTABUP: { + int a = GETARG_A(instr); + settable(ks, cl->upvals[a]->v, RKB(instr), RKC(instr)); + base = ci->u.l.base; + break; + } + case OP_SETTABUP_INCR: { + int a = GETARG_A(instr); + settable_incr(ks, cl->upvals[a]->v, RKB(instr), RKC(instr)); + base = ci->u.l.base; + break; + } + case OP_SETUPVAL: { + ktap_upval *uv = cl->upvals[GETARG_B(instr)]; + setobj(uv->v, ra); + break; + } + case OP_SETTABLE: + settable(ks, ra, RKB(instr), RKC(instr)); + base = ci->u.l.base; + break; + case OP_SETTABLE_INCR: + settable_incr(ks, ra, RKB(instr), RKC(instr)); + base = ci->u.l.base; + break; + case OP_NEWTABLE: { + int b = GETARG_B(instr); + int c = GETARG_C(instr); + ktap_table *t = kp_table_new(ks); + sethvalue(ra, t); + if (b != 0 || c != 0) + kp_table_resize(ks, t, fb2int(b), fb2int(c)); + break; + } + case OP_SELF: { + StkId rb = RB(instr); + setobj(ra+1, rb); + gettable(ks, rb, RKC(instr), ra); + base = ci->u.l.base; + break; + } + case OP_ADD: + arith_op(ks, NUMADD); + break; + case OP_SUB: + arith_op(ks, NUMSUB); + break; + case OP_MUL: + arith_op(ks, NUMMUL); + break; + case OP_DIV: + /* divide 0 checking */ + if (!nvalue(RKC(instr))) { + kp_error(ks, "divide 0 arith operation\n"); + return; + } + arith_op(ks, NUMDIV); + break; + case OP_MOD: + /* divide 0 checking */ + if (!nvalue(RKC(instr))) { + kp_error(ks, "mod 0 arith operation\n"); + return; + } + arith_op(ks, NUMMOD); + break; + case OP_POW: + kp_error(ks, "ktap don't support pow arith in kernel\n"); + return; + case OP_UNM: { + ktap_value *rb = RB(instr); + if (ttisnumber(rb)) { + ktap_number nb = nvalue(rb); + setnvalue(ra, NUMUNM(nb)); + } + break; + } + case OP_NOT: + res = isfalse(RB(instr)); + setbvalue(ra, res); + break; + case OP_LEN: { + int len = kp_objlen(ks, RB(instr)); + if (len < 0) + return; + setnvalue(ra, len); + break; + } + case OP_CONCAT: { + int b = GETARG_B(instr); + int c = GETARG_C(instr); + ktap_concat(ks, b, c); + break; + } + case OP_JMP: + dojump(ci, instr, 0); + break; + case OP_EQ: { + ktap_value *rb = RKB(instr); + ktap_value *rc = RKC(instr); + if ((int)equalobj(ks, rb, rc) != GETARG_A(instr)) + ci->u.l.savedpc++; + else + donextjump(ci); + + base = ci->u.l.base; + break; + } + case OP_LT: + if (lessthan(ks, RKB(instr), RKC(instr)) != GETARG_A(instr)) + ci->u.l.savedpc++; + else + donextjump(ci); + base = ci->u.l.base; + break; + case OP_LE: + if (lessequal(ks, RKB(instr), RKC(instr)) != GETARG_A(instr)) + ci->u.l.savedpc++; + else + donextjump(ci); + base = ci->u.l.base; + break; + case OP_TEST: + if (GETARG_C(instr) ? isfalse(ra) : !isfalse(ra)) + ci->u.l.savedpc++; + else + donextjump(ci); + break; + case OP_TESTSET: { + ktap_value *rb = RB(instr); + if (GETARG_C(instr) ? isfalse(rb) : !isfalse(rb)) + ci->u.l.savedpc++; + else { + setobj(ra, rb); + donextjump(ci); + } + break; + } + case OP_CALL: { + int b = GETARG_B(instr); + int ret; + + nresults = GETARG_C(instr) - 1; + + if (b != 0) + ks->top = ra + b; + + ret = precall(ks, ra, nresults); + if (ret) { /* C function */ + if (nresults >= 0) + ks->top = ci->top; + base = ci->u.l.base; + break; + } else { /* ktap function */ + ci = ks->ci; + /* this flag is used for return time, see OP_RETURN */ + ci->callstatus |= CIST_REENTRY; + goto newframe; + } + break; + } + case OP_TAILCALL: { + int b = GETARG_B(instr); + + if (b != 0) + ks->top = ra+b; + if (precall(ks, ra, -1)) /* C function? */ + base = ci->u.l.base; + else { + int aux; + + /* + * tail call: put called frame (n) in place of + * caller one (o) + */ + ktap_callinfo *nci = ks->ci; /* called frame */ + ktap_callinfo *oci = nci->prev; /* caller frame */ + StkId nfunc = nci->func; /* called function */ + StkId ofunc = oci->func; /* caller function */ + /* last stack slot filled by 'precall' */ + StkId lim = nci->u.l.base + + CLVALUE(nfunc)->p->numparams; + + /* close all upvalues from previous call */ + if (cl->p->sizep > 0) + function_close(ks, oci->u.l.base); + + /* move new frame into old one */ + for (aux = 0; nfunc + aux < lim; aux++) + setobj(ofunc + aux, nfunc + aux); + /* correct base */ + oci->u.l.base = ofunc + (nci->u.l.base - nfunc); + /* correct top */ + oci->top = ks->top = ofunc + (ks->top - nfunc); + oci->u.l.savedpc = nci->u.l.savedpc; + /* remove new frame */ + ci = ks->ci = oci; + /* restart ktap_execute over new ktap function */ + goto newframe; + } + break; + } + case OP_RETURN: { + int b = GETARG_B(instr); + if (b != 0) + ks->top = ra+b-1; + if (cl->p->sizep > 0) + function_close(ks, base); + b = poscall(ks, ra); + + /* if it's called from external invocation, just return */ + if (!(ci->callstatus & CIST_REENTRY)) + return; + + ci = ks->ci; + if (b) + ks->top = ci->top; + goto newframe; + } + case OP_FORLOOP: { + ktap_number step = nvalue(ra+2); + /* increment index */ + ktap_number idx = NUMADD(nvalue(ra), step); + ktap_number limit = nvalue(ra+1); + if (NUMLT(0, step) ? NUMLE(idx, limit) : NUMLE(limit, idx)) { + ci->u.l.savedpc += GETARG_sBx(instr); /* jump back */ + setnvalue(ra, idx); /* update internal index... */ + setnvalue(ra+3, idx); /* ...and external index */ + } + break; + } + case OP_FORPREP: { + const ktap_value *init = ra; + const ktap_value *plimit = ra + 1; + const ktap_value *pstep = ra + 2; + + if (!ktap_tonumber(init, ra)) { + kp_error(ks, KTAP_QL("for") + " initial value must be a number\n"); + return; + } else if (!ktap_tonumber(plimit, ra + 1)) { + kp_error(ks, KTAP_QL("for") + " limit must be a number\n"); + return; + } else if (!ktap_tonumber(pstep, ra + 2)) { + kp_error(ks, KTAP_QL("for") " step must be a number\n"); + return; + } + + setnvalue(ra, NUMSUB(nvalue(ra), nvalue(pstep))); + ci->u.l.savedpc += GETARG_sBx(instr); + break; + } + case OP_TFORCALL: { + StkId cb = ra + 3; /* call base */ + setobj(cb + 2, ra + 2); + setobj(cb + 1, ra + 1); + setobj(cb, ra); + ks->top = cb + 3; /* func. + 2 args (state and index) */ + kp_call(ks, cb, GETARG_C(instr)); + base = ci->u.l.base; + ks->top = ci->top; + instr = *(ci->u.l.savedpc++); /* go to next instruction */ + ra = RA(instr); + } + /*go through */ + case OP_TFORLOOP: + if (!ttisnil(ra + 1)) { /* continue loop? */ + setobj(ra, ra + 1); /* save control variable */ + ci->u.l.savedpc += GETARG_sBx(instr); /* jump back */ + } + break; + case OP_SETLIST: { + int n = GETARG_B(instr); + int c = GETARG_C(instr); + int last; + ktap_table *h; + + if (n == 0) + n = (int)(ks->top - ra) - 1; + if (c == 0) + c = GETARG_Ax(*ci->u.l.savedpc++); + + h = hvalue(ra); + last = ((c - 1) * LFIELDS_PER_FLUSH) + n; + if (last > h->sizearray) /* needs more space? */ + kp_table_resizearray(ks, h, last); + + for (; n > 0; n--) { + ktap_value *val = ra+n; + kp_table_setint(ks, h, last--, val); + } + /* correct top (in case of previous open call) */ + ks->top = ci->top; + break; + } + case OP_CLOSURE: { + /* need to use closure cache? (multithread contention issue)*/ + ktap_proto *p = cl->p->p[GETARG_Bx(instr)]; + pushclosure(ks, p, cl->upvals, base, ra); + break; + } + case OP_VARARG: { + int b = GETARG_B(instr) - 1; + int j; + int n = (int)(base - ci->func) - cl->p->numparams - 1; + if (b < 0) { /* B == 0? */ + b = n; /* get all var. arguments */ + checkstack(ks, n); + /* previous call may change the stack */ + ra = RA(instr); + ks->top = ra + n; + } + for (j = 0; j < b; j++) { + if (j < n) { + setobj(ra + j, base - n + j); + } else + setnilvalue(ra + j); + } + break; + } + case OP_EXTRAARG: + return; + + case OP_EVENT: { + struct ktap_event *e = ks->current_event; + + if (unlikely(!e)) { + kp_error(ks, "invalid event context\n"); + return; + } + setevalue(ra, e); + break; + } + + case OP_EVENTNAME: { + struct ktap_event *e = ks->current_event; + + if (unlikely(!e)) { + kp_error(ks, "invalid event context\n"); + return; + } + setsvalue(ra, kp_tstring_new(ks, e->call->name)); + break; + } + case OP_EVENTARG: + if (unlikely(!ks->current_event)) { + kp_error(ks, "invalid event context\n"); + return; + } + + kp_event_getarg(ks, ra, GETARG_B(instr)); + break; + case OP_LOAD_GLOBAL: { + ktap_value *cfunc = cfunction_cache_get(ks, GETARG_C(instr)); + setobj(ra, cfunc); + } + break; + + case OP_EXIT: + return; + } + + goto mainloop; +} + +void kp_call(ktap_state *ks, StkId func, int nresults) +{ + if (!precall(ks, func, nresults)) + ktap_execute(ks); +} + +static int cfunction_cache_getindex(ktap_state *ks, ktap_value *fname); + +/* + * This function must be called before all code loaded. + */ +void kp_optimize_code(ktap_state *ks, int level, ktap_proto *f) +{ + int i; + + for (i = 0; i < f->sizecode; i++) { + int instr = f->code[i]; + ktap_value *k = f->k; + + if (GET_OPCODE(instr) == OP_GETTABUP) { + if ((GETARG_B(instr) == 0) && ISK(GETARG_C(instr))) { + ktap_value *field = k + INDEXK(GETARG_C(instr)); + if (ttype(field) == KTAP_TSTRING) { + int index = cfunction_cache_getindex(ks, + field); + if (index == -1) + break; + + SET_OPCODE(instr, OP_LOAD_GLOBAL); + SETARG_C(instr, index); + f->code[i] = instr; + break; + } + } + } + } + + /* continue optimize sub functions */ + for (i = 0; i < f->sizep; i++) + kp_optimize_code(ks, level + 1, f->p[i]); +} + +static ktap_value *cfunction_cache_get(ktap_state *ks, int index) +{ + return &G(ks)->cfunction_tbl[index]; +} + +static int cfunction_cache_getindex(ktap_state *ks, ktap_value *fname) +{ + const ktap_value *gt = kp_table_getint(hvalue(&G(ks)->registry), + KTAP_RIDX_GLOBALS); + const ktap_value *cfunc; + int nr, i; + + nr = G(ks)->nr_builtin_cfunction; + cfunc = kp_table_get(hvalue(gt), fname); + + for (i = 0; i < nr; i++) { + if (rawequalobj(&G(ks)->cfunction_tbl[i], cfunc)) + return i; + } + + return -1; +} + +static void cfunction_cache_add(ktap_state *ks, ktap_value *func) +{ + int nr = G(ks)->nr_builtin_cfunction; + setobj(&G(ks)->cfunction_tbl[nr], func); + G(ks)->nr_builtin_cfunction++; +} + +static void cfunction_cache_exit(ktap_state *ks) +{ + kp_free(ks, G(ks)->cfunction_tbl); +} + +static int cfunction_cache_init(ktap_state *ks) +{ + G(ks)->cfunction_tbl = kp_zalloc(ks, sizeof(ktap_value) * 128); + if (!G(ks)->cfunction_tbl) + return -ENOMEM; + + return 0; +} + +/* function for register library */ +void kp_register_lib(ktap_state *ks, const char *libname, const ktap_Reg *funcs) +{ + int i; + ktap_table *target_tbl; + const ktap_value *gt = kp_table_getint(hvalue(&G(ks)->registry), + KTAP_RIDX_GLOBALS); + + /* lib is null when register baselib function */ + if (libname == NULL) + target_tbl = hvalue(gt); + else { + ktap_value key, val; + + target_tbl = kp_table_new(ks); + kp_table_resize(ks, target_tbl, 0, + sizeof(*funcs) / sizeof(ktap_Reg)); + + setsvalue(&key, kp_tstring_new(ks, libname)); + sethvalue(&val, target_tbl); + kp_table_setvalue(ks, hvalue(gt), &key, &val); + } + + for (i = 0; funcs[i].name != NULL; i++) { + ktap_value func_name, cl; + + setsvalue(&func_name, kp_tstring_new(ks, funcs[i].name)); + setfvalue(&cl, funcs[i].func); + kp_table_setvalue(ks, target_tbl, &func_name, &cl); + + cfunction_cache_add(ks, &cl); + } +} + +#define BASIC_STACK_SIZE (2 * KTAP_MINSTACK) + +static void kp_init_registry(ktap_state *ks) +{ + ktap_value mt; + ktap_table *registry = kp_table_new(ks); + + sethvalue(&G(ks)->registry, registry); + kp_table_resize(ks, registry, KTAP_RIDX_LAST, 0); + setthvalue(ks, &mt, ks); + kp_table_setint(ks, registry, KTAP_RIDX_MAINTHREAD, &mt); + sethvalue(&mt, kp_table_new(ks)); + kp_table_setint(ks, registry, KTAP_RIDX_GLOBALS, &mt); +} + +static int kp_init_arguments(ktap_state *ks, int argc, char __user **user_argv) +{ + const ktap_value *gt = kp_table_getint(hvalue(&G(ks)->registry), + KTAP_RIDX_GLOBALS); + ktap_table *global_tbl = hvalue(gt); + ktap_table *arg_tbl = kp_table_new(ks); + ktap_value arg_tblval; + ktap_value arg_tsval; + char **argv; + int i, ret; + + setsvalue(&arg_tsval, kp_tstring_new(ks, "arg")); + sethvalue(&arg_tblval, arg_tbl); + kp_table_setvalue(ks, global_tbl, &arg_tsval, &arg_tblval); + + if (!argc) + return 0; + + if (argc > 1024) + return -EINVAL; + + argv = kzalloc(argc * sizeof(char *), GFP_KERNEL); + if (!argv) + return -ENOMEM; + + ret = copy_from_user(argv, user_argv, argc * sizeof(char *)); + if (ret < 0) { + kfree(argv); + return -EFAULT; + } + + kp_table_resize(ks, arg_tbl, argc, 1); + + ret = 0; + for (i = 0; i < argc; i++) { + ktap_value val; + char __user *ustr = argv[i]; + char * kstr; + int len; + int res; + + len = strlen_user(ustr); + if (len > 0x1000) { + ret = -EINVAL; + break; + } + + kstr = kmalloc(len + 1, GFP_KERNEL); + if (!kstr) { + ret = -ENOMEM; + break; + } + + if (strncpy_from_user(kstr, ustr, len) < 0) { + ret = -EFAULT; + break; + } + + kstr[len] = '\0'; + + if (!kstrtoint(kstr, 10, &res)) { + setnvalue(&val, res); + } else + setsvalue(&val, kp_tstring_new(ks, kstr)); + + kp_table_setint(ks, arg_tbl, i, &val); + + kfree(kstr); + } + + kfree(argv); + return ret; +} + +DEFINE_PER_CPU(int, kp_recursion_context[PERF_NR_CONTEXTS]); + +/* todo: make this per-session aware */ +static void __percpu *kp_pcpu_data[KTAP_PERCPU_DATA_MAX][PERF_NR_CONTEXTS]; + +void *kp_percpu_data(int type) +{ + return this_cpu_ptr(kp_pcpu_data[type][trace_get_context_bit()]); +} + +static void free_kp_percpu_data(void) +{ + int i, j; + + for (i = 0; i < KTAP_PERCPU_DATA_MAX; i++) { + for (j = 0; j < PERF_NR_CONTEXTS; j++) { + free_percpu(kp_pcpu_data[i][j]); + kp_pcpu_data[i][j] = NULL; + } + } +} + +static int alloc_kp_percpu_data(void) +{ + int data_size[KTAP_PERCPU_DATA_MAX] = { + sizeof(ktap_state), KTAP_STACK_SIZE, KTAP_PERCPU_BUFFER_SIZE, + KTAP_PERCPU_BUFFER_SIZE, sizeof(ktap_btrace)}; + int i, j; + + for (i = 0; i < KTAP_PERCPU_DATA_MAX; i++) { + for (j = 0; j < PERF_NR_CONTEXTS; j++) { + void __percpu *data = __alloc_percpu(data_size[i], + __alignof__(char)); + if (!data) + goto fail; + kp_pcpu_data[i][j] = data; + } + } + + return 0; + + fail: + free_kp_percpu_data(); + return -ENOMEM; +} + +static void kp_init_state(ktap_state *ks) +{ + ktap_callinfo *ci; + int i; + + ks->stacksize = BASIC_STACK_SIZE; + + for (i = 0; i < BASIC_STACK_SIZE; i++) + setnilvalue(ks->stack + i); + + ks->top = ks->stack; + ks->stack_last = ks->stack + ks->stacksize; + + ci = &ks->baseci; + ci->callstatus = 0; + ci->func = ks->top; + setnilvalue(ks->top++); + ci->top = ks->top + KTAP_MINSTACK; + ks->ci = ci; +} + +static void free_all_ci(ktap_state *ks) +{ + int cpu; + + for_each_possible_cpu(cpu) { + ktap_state *ks; + int j; + + for (j = 0; j < PERF_NR_CONTEXTS; j++) { + if (!kp_pcpu_data[KTAP_PERCPU_DATA_STATE][j]) + break; + + ks = per_cpu_ptr(kp_pcpu_data[KTAP_PERCPU_DATA_STATE][j], cpu); + if (!ks) + break; + + free_ci(ks); + } + } + + free_ci(ks); +} + +void kp_exitthread(ktap_state *ks) +{ + /* free local allocation objects, like annotate strings */ + kp_free_gclist(ks, ks->gclist); +} + +ktap_state *kp_newthread(ktap_state *mainthread) +{ + ktap_state *ks; + + ks = kp_percpu_data(KTAP_PERCPU_DATA_STATE); + ks->stack = kp_percpu_data(KTAP_PERCPU_DATA_STACK); + G(ks) = G(mainthread); + ks->gclist = NULL; + kp_init_state(ks); + return ks; +} + +/* + * wait ktapio thread read all content in ring buffer. + * + * Here we use stupid approach to sync with ktapio thread, + * note that we cannot use semaphore/completion/other sync method, + * because ktapio thread could be killed by SIG_KILL in anytime, there + * have no safe way to up semaphore or wake waitqueue before thread exit. + * + * we also cannot use waitqueue of current->signal->wait_chldexit to sync + * exit, becasue mainthread and ktapio thread are in same thread group. + * + * Also ktap mainthread must wait ktapio thread exit, otherwise ktapio + * thread will oops when access ktap structure. + */ +static void wait_user_completion(ktap_state *ks) +{ + struct task_struct *tsk = G(ks)->task; + G(ks)->wait_user = 1; + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + /* sleep for 100 msecs, and try again. */ + schedule_timeout(HZ / 10); + + if (get_nr_threads(tsk) == 1) + break; + } +} + +/* kp_wait: used for mainthread waiting for exit */ +static void kp_wait(ktap_state *ks) +{ + struct task_struct *task = G(ks)->trace_task; + + if (G(ks)->exit) + return; + + ks->stop = 0; + + /* tell workload process to start executing */ + if (G(ks)->parm->workload) + send_sig(SIGINT, G(ks)->trace_task, 0); + + while (!ks->stop) { + set_current_state(TASK_INTERRUPTIBLE); + /* sleep for 100 msecs, and try again. */ + schedule_timeout(HZ / 10); + + if (signal_pending(current)) { + flush_signals(current); + + /* newline for handle CTRL+C display as ^C */ + kp_puts(ks, "\n"); + break; + } + + /* stop waiting if target pid is exited */ + if (task && task->state == TASK_DEAD) + break; + } + +} + +void kp_exit(ktap_state *ks) +{ + set_next_as_exit(ks); + + G(ks)->mainthread->stop = 1; + G(ks)->exit = 1; +} + +void kp_final_exit(ktap_state *ks) +{ + if (!list_empty(&G(ks)->probe_events_head) || + !list_empty(&G(ks)->timers)) + kp_wait(ks); + + if (G(ks)->trace_task) + put_task_struct(G(ks)->trace_task); + + kp_exit_timers(ks); + kp_probe_exit(ks); + + /* free all resources got by ktap */ + kp_tstring_freeall(ks); + kp_free_all_gcobject(ks); + cfunction_cache_exit(ks); + + wait_user_completion(ks); + + kp_transport_exit(ks); + + kp_exitthread(ks); + kp_free(ks, ks->stack); + free_all_ci(ks); + + free_kp_percpu_data(); + + free_cpumask_var(G(ks)->cpumask); + kp_free(ks, ks); +} + +/* ktap mainthread initization, main entry for ktap */ +ktap_state *kp_newstate(ktap_parm *parm, struct dentry *dir) +{ + ktap_state *ks; + pid_t pid; + int cpu; + + ks = kzalloc(sizeof(ktap_state) + sizeof(ktap_global_state), + GFP_KERNEL); + if (!ks) + return NULL; + + ks->stack = kp_malloc(ks, KTAP_STACK_SIZE); + G(ks) = (ktap_global_state *)(ks + 1); + G(ks)->mainthread = ks; + G(ks)->seed = 201236; /* todo: make more random in future */ + G(ks)->task = current; + G(ks)->parm = parm; + INIT_LIST_HEAD(&(G(ks)->timers)); + INIT_LIST_HEAD(&(G(ks)->probe_events_head)); + G(ks)->exit = 0; + + if (kp_transport_init(ks, dir)) + goto out; + + pid = (pid_t)parm->trace_pid; + if (pid != -1) { + struct task_struct *task; + + rcu_read_lock(); + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if (!task) { + kp_error(ks, "cannot find pid %d\n", pid); + rcu_read_unlock(); + goto out; + } + G(ks)->trace_task = task; + get_task_struct(task); + rcu_read_unlock(); + } + + if( !alloc_cpumask_var(&G(ks)->cpumask, GFP_KERNEL)) + goto out; + + cpumask_copy(G(ks)->cpumask, cpu_online_mask); + + cpu = parm->trace_cpu; + if (cpu != -1) { + if (!cpu_online(cpu)) { + printk(KERN_INFO "ktap: cpu %d is not online\n", cpu); + goto out; + } + + cpumask_clear(G(ks)->cpumask); + cpumask_set_cpu(cpu, G(ks)->cpumask); + } + + if (cfunction_cache_init(ks)) + goto out; + + kp_tstring_resize(ks, 512); /* set inital string hashtable size */ + + kp_init_state(ks); + kp_init_registry(ks); + kp_init_arguments(ks, parm->argc, parm->argv); + + /* init library */ + kp_init_baselib(ks); + kp_init_kdebuglib(ks); + kp_init_timerlib(ks); + kp_init_ansilib(ks); + + if (alloc_kp_percpu_data()) + goto out; + + if (kp_probe_init(ks)) + goto out; + + return ks; + + out: + G(ks)->exit = 1; + kp_final_exit(ks); + return NULL; +} + diff --git a/drivers/staging/ktap/scripts/basic/backtrace.kp b/drivers/staging/ktap/scripts/basic/backtrace.kp new file mode 100644 index 000000000000..39b8c3989e7f --- /dev/null +++ b/drivers/staging/ktap/scripts/basic/backtrace.kp @@ -0,0 +1,6 @@ +#!/usr/bin/env ktap + +trace sched:sched_switch { + print_backtrace() +} + diff --git a/drivers/staging/ktap/scripts/basic/event_trigger.kp b/drivers/staging/ktap/scripts/basic/event_trigger.kp new file mode 100644 index 000000000000..3cc8b04f361e --- /dev/null +++ b/drivers/staging/ktap/scripts/basic/event_trigger.kp @@ -0,0 +1,24 @@ +#!/usr/bin/env ktap + +soft_disabled = 1 +this_cpu = 0 + +trace syscalls:sys_enter_open { + print(argevent) + soft_disabled = 0 + this_cpu = cpu() +} + +trace *:* { + if (soft_disabled == 0 && cpu() == this_cpu) { + print(argevent) + } +} + +trace syscalls:sys_exit_open { + print(argevent) + if (cpu() == this_cpu) { + exit() + } +} + diff --git a/drivers/staging/ktap/scripts/basic/event_trigger_ftrace.kp b/drivers/staging/ktap/scripts/basic/event_trigger_ftrace.kp new file mode 100644 index 000000000000..7e0d7d315619 --- /dev/null +++ b/drivers/staging/ktap/scripts/basic/event_trigger_ftrace.kp @@ -0,0 +1,28 @@ +#!/usr/bin/env ktap + + +#This ktap script will output all function calling between +#sys_enter_open and sys_exit_open, in one cpu. + +soft_disabled = 1 +this_cpu = 0 + +trace syscalls:sys_enter_open { + print(argevent) + soft_disabled = 0 + this_cpu = cpu() +} + +trace ftrace:function { + if (soft_disabled == 0 && cpu() == this_cpu) { + print(argevent) + } +} + +trace syscalls:sys_exit_open { + print(argevent) + if (cpu() == this_cpu) { + exit() + } +} + diff --git a/drivers/staging/ktap/scripts/basic/ftrace.kp b/drivers/staging/ktap/scripts/basic/ftrace.kp new file mode 100644 index 000000000000..9feca2ba2318 --- /dev/null +++ b/drivers/staging/ktap/scripts/basic/ftrace.kp @@ -0,0 +1,6 @@ +#!/usr/bin/env ktap + +trace ftrace:function /ip==mutex*/ { + print(cpu(), pid(), execname(), argevent) +} + diff --git a/drivers/staging/ktap/scripts/basic/function_time.kp b/drivers/staging/ktap/scripts/basic/function_time.kp new file mode 100644 index 000000000000..e7859a396d95 --- /dev/null +++ b/drivers/staging/ktap/scripts/basic/function_time.kp @@ -0,0 +1,57 @@ +#!/usr/bin/env ktap + +#Demo for thread-local variable +# +#Note this kind of function time tracing already handled concurrent issue, +#but not aware on the recursion problem, user need to aware this limitation, +#so don't use this script to trace function which could be called recursive. + +self = {} +count_max = 0 +count_min = 0 +count_num = 0 +total_time = 0 + +printf("measure time(us) of function vfs_read\n"); + +trace probe:vfs_read { + if (execname() == "ktap") { + return + } + + self[tid()] = gettimeofday_us() +} + +trace probe:vfs_read%return { + if (execname() == "ktap") { + return + } + + if (self[tid()] == nil) { + return + } + + local durtion = gettimeofday_us() - self[tid()] + if (durtion > count_max) { + count_max = durtion + } + local min = count_min + if (min == 0 || durtion < min) { + count_min = durtion + } + + count_num = count_num + 1 + total_time = total_time + durtion + + self[tid()] = nil +} + +trace_end { + printf("avg\tmax\tmin\n"); + printf("-------------------\n") + + printf("%d\t%d\t%d\n", total_time/count_num, + count_max, count_min) +} + + diff --git a/drivers/staging/ktap/scripts/basic/kretprobe.kp b/drivers/staging/ktap/scripts/basic/kretprobe.kp new file mode 100644 index 000000000000..82de3cffa276 --- /dev/null +++ b/drivers/staging/ktap/scripts/basic/kretprobe.kp @@ -0,0 +1,6 @@ +#!/usr/bin/env ktap + +trace probe:vfs_read%return fd=$retval { + print(execname(), argevent); +} + diff --git a/drivers/staging/ktap/scripts/game/tetris.kp b/drivers/staging/ktap/scripts/game/tetris.kp new file mode 100644 index 000000000000..7125cd4e46ce --- /dev/null +++ b/drivers/staging/ktap/scripts/game/tetris.kp @@ -0,0 +1,328 @@ +#!/usr/bin/env ktap + +# +# Tetris KTAP Script +# +# Copyright (C) 2013/OCT/05 Tadaki SAKAI +# +# based on stapgames (Systemtap Game Collection) +# https://github.com/mhiramat/stapgames/blob/master/games/tetris.stp +# +# - Requirements +# Kernel Configuration: CONFIG_KPROBE_EVENT=y +# CONFIG_EVENT_TRACING=y +# CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_FS=y +# CPU Architecture : x86_64 +# +# - Setup +# $ sudo mount -t debugfs none /sys/kernel/debug/ +# +# $ git clone https://github.com/ktap/ktap +# $ cd ktap +# $ make 2>&1 | tee ../make.log +# $ sudo make load +# $ sudo sh -c 'echo 50000 > /sys/module/ktapvm/parameters/max_exec_count' +# +# - Run Tetris +# $ sudo ./ktap scripts/game/tetris.kp +# + + +# +# utils +# + +function rand(max) { + r = gettimeofday_us() + if (r < 0) { + r = r * -1 + } + return r % max +} + +color_table = {} +color_table["Black"] = 40 +color_table["Red"] = 41 +color_table["Green"] = 42 +color_table["Yellow"] = 43 +color_table["Blue"] = 44 +color_table["Purple"] = 45 +color_table["Cyan"] = 46 +color_table["White"] = 47 + +function get_color_number(txt) { + return color_table[txt] +} + +color_table_text = {} +color_table_text[40] = "Black" +color_table_text[41] = "Red" +color_table_text[42] = "Green" +color_table_text[43] = "Yellow" +color_table_text[44] = "Blue" +color_table_text[45] = "Purple" +color_table_text[46] = "Cyan" +color_table_text[47] = "White" + +function get_color_text(num) { + return color_table_text[num] +} + +function update_display() { + for (i = 0, 239, 1) { + if ((i % 12 - 11) != 0) { + tmp = "" + } else { + tmp = "\n" + } + + if (display_buffer[240 + i] == back_text) { + printf("%s%s", back_text, tmp) + } else { + ctext = display_buffer[240 + i] + ansi.set_color2(get_color_number(ctext), + get_color_number(ctext)) + printf(" %s", tmp) + ansi.reset_color() + } + + # clear the display buffer + display_buffer[240 + i] = display_buffer[i] + } + + printf("%d\n",point) +} + + +# +# global value +# + +key_code = 0 +point = 0 +block_number = 0 +height = 0 +height_update = 0 + +destination_position = {} +back_text = {} +block_color = {} +display_buffer = {} + +block_data0 = {} +block_data1 = {} +block_data2 = {} +block_data3 = {} +block_data4 = {} +block_data5 = {} +block_data6 = {} +block_table = {} + +# +# Initialize +# + +# Create blocks +# block is represented by the position from the center. +# Every block has "L" part in the center except for a bar. +block_data0[0] = -11 # non-"L" part for each block +block_data1[0] = -24 +block_data2[0] = 2 +block_data3[0] = 13 +block_data4[0] = -13 +block_data5[0] = -1 +block_data6[0] = 2 + +block_table[0] = block_data0 +block_table[1] = block_data1 +block_table[2] = block_data2 +block_table[3] = block_data3 +block_table[4] = block_data4 +block_table[5] = block_data5 +block_table[6] = block_data6 + +for (i = 0, len(block_table) - 1, 1) { + # common "L" part + block_table[i][1] = 0 + block_table[i][2] = 1 + block_table[i][3] = -12 +} + +block_table[6][3] = -1 # bar is not common +# Position: 1 row has 12 columns, +# and (x, y) is represented by h = x + y * 12.p +height = 17 # First block position (center) + +for (i = 0, 240, 1) { + # Wall and Floor (sentinel) + if (((i % 12) < 2) || (i > 228)) { + block_color = "White" + tmp = block_color + } else { + back_text = " " + tmp = back_text + } + display_buffer[i - 1] = tmp + display_buffer[240 + i - 1] = tmp +} + +block_number = rand(len(color_table) - 1) +block_color = get_color_text(block_number + 40) + +ansi.clear_screen() + + +# +# Key Input +# + +trace probe:kbd_event handle=%di event_type=%si event_code=%dx value=%cx { + # Only can run it in x86_64 + # + # Register follow x86_64 call conversion: + # + # x86_64: + # %rcx 4 argument + # %rdx 3 argument + # %rsi 2 argument + # %rdi 1 argument + + local event_code = arg4 + local value = arg5 + + if (value != 0) { + if ((event_code - 4) != 0) { + key_code = event_code + } + } +} + + +# +# timer +# + +tick-200ms { + ansi.clear_screen() + + f = 0 # move/rotate flag + + if (key_code != 0) { # if key is pressed + if(key_code != 103) { #move left or right + # d: movement direction + if ((key_code - 105) != 0) { + if ((key_code - 106) != 0) { + d = 0 + } else { + d = 1 + } + } else { + d = -1 + } + + for (i = 0, 3, 1) { # check if the block can be moved + # destination is free + if (display_buffer[height + + block_table[block_number][i] + d] + != back_text) { + f = 1 + } + } + # move if destinations of every block are free + if (f == 0) { + height = height + d + } + } else { # rotate + for (i = 0, 3, 1) { # check if block can be rotated + # each block position + p = block_table[block_number][i] + + # destination x pos(p/12 rounded) + v = (p * 2 + 252) / 24 - 10 + w = p - v * 12 # destination y pos + + # destination position + destination_position[i] = w * 12 - v + + # check if desetination is free + if (display_buffer[height + + destination_position[i]] != back_text) { + f = 1 + } + } + + if (f == 0) { + # rotate if destinations of every block + # are free + for (i = 0, 3, 1) { + block_table[block_number][i] = + destination_position[i] + } + } + } + } + key_code = 0 # clear the input key + + f = 0 + for (i = 0, 3, 1) { # drop 1 row + # check if destination is free + p = height + block_table[block_number][i] + if (display_buffer[12 + p] != back_text) { + f = 1 + } + + # copy the moving block to display buffer + display_buffer[240 + p] = block_color + } + + if ((f == 1) && (height == 17)) { + update_display() + exit() # exit if there are block at initial position + } + + height_update = !height_update + if (height_update != 0) { + if(f != 0) { # the block can't drop anymore + for (i = 0, 3, 1) { + # fix the block + display_buffer[height + + block_table[block_number][i]] = block_color + } + # determin the next block + block_number = rand(len(color_table) - 1) + + block_color = get_color_text(block_number + 40) + + height = 17 # make the block to initial position + } else { + height = height + 12 # drop the block 1 row + } + } + + k = 1 + for (i = 18, 0, -1) { #check if line is filled + # search for filled line + j = 10 + while ((j > 0) && + (display_buffer[i * 12 + j] != back_text)) { + j = j - 1 + } + + if (j == 0) { # filled! + # add a point: 1 line - 1 point, ..., tetris - 10points + point = point + k + k = k + 1 + + # drop every upper block + j = (i + 1) * 12 + i = i + 1 + while (j > 2 * 12) { + j = j - 1 + display_buffer[j] = display_buffer[j - 12] + } + } + } + + update_display() +} diff --git a/drivers/staging/ktap/scripts/helloworld.kp b/drivers/staging/ktap/scripts/helloworld.kp new file mode 100644 index 000000000000..5673c15b0226 --- /dev/null +++ b/drivers/staging/ktap/scripts/helloworld.kp @@ -0,0 +1,3 @@ +#!/usr/bin/env ktap + +print("Hello World! I am ktap") diff --git a/drivers/staging/ktap/scripts/interrupt/hardirq_time.kp b/drivers/staging/ktap/scripts/interrupt/hardirq_time.kp new file mode 100644 index 000000000000..1d3c33e859d1 --- /dev/null +++ b/drivers/staging/ktap/scripts/interrupt/hardirq_time.kp @@ -0,0 +1,25 @@ +#!/usr/bin/env ktap + +#this script output each average consumimg time of each hardirq +s = aggr_table() +map = {} + +trace irq:irq_handler_entry { + map[cpu()] = gettimeofday_us() +} + +trace irq:irq_handler_exit { + local entry_time = map[cpu()] + if (entry_time == nil) { + return; + } + + s[arg1] = avg(gettimeofday_us() - entry_time) + map[cpu()] = nil +} + +trace_end { + print("hardirq average executing time (us)") + histogram(s) +} + diff --git a/drivers/staging/ktap/scripts/interrupt/softirq_time.kp b/drivers/staging/ktap/scripts/interrupt/softirq_time.kp new file mode 100644 index 000000000000..7e1a9d8a9172 --- /dev/null +++ b/drivers/staging/ktap/scripts/interrupt/softirq_time.kp @@ -0,0 +1,25 @@ +#!/usr/bin/env ktap + +#this script output each average consumimg time of each softirq line +s = aggr_table() +map = {} + +trace irq:softirq_entry { + map[cpu()] = gettimeofday_us() +} + +trace irq:softirq_exit { + local entry_time = map[cpu()] + if (entry_time == nil) { + return; + } + + s[arg1] = avg(gettimeofday_us() - entry_time) + map[cpu()] = nil +} + +trace_end { + print("softirq average executing time (us)") + histogram(s) +} + diff --git a/drivers/staging/ktap/scripts/io/kprobes-do-sys-open.kp b/drivers/staging/ktap/scripts/io/kprobes-do-sys-open.kp new file mode 100644 index 000000000000..a15f911a1804 --- /dev/null +++ b/drivers/staging/ktap/scripts/io/kprobes-do-sys-open.kp @@ -0,0 +1,20 @@ +#!/usr/bin/env ktap + +#Only can run it in x86_64 +# +#Register follow x86_64 call conversion: +# +#x86_64: +# %rcx 4 argument +# %rdx 3 argument +# %rsi 2 argument +# %rdi 1 argument + +trace probe:do_sys_open dfd=%di filename=%si flags=%dx mode=%cx { + printf("[do_sys_open entry]: (%s) open file (%s)\n", + execname(), user_string(arg3)) +} + +trace probe:do_sys_open%return fd=$retval { + printf("[do_sys_open exit]: return fd (%d)\n", arg3) +} diff --git a/drivers/staging/ktap/scripts/io/traceio.kp b/drivers/staging/ktap/scripts/io/traceio.kp new file mode 100644 index 000000000000..8a95a2534384 --- /dev/null +++ b/drivers/staging/ktap/scripts/io/traceio.kp @@ -0,0 +1,56 @@ +#! /usr/bin/env ktap + +# Based on systemtap traceio.stp + +#this script is broken, fix it soon. + +reads = aggr_table() +writes = aggr_table() +total_io = aggr_table() + +trace syscalls:sys_exit_read { + reads[execname()] = sum(arg2) + total_io[execname()] = sum(arg2) +} + +trace syscalls:sys_exit_write { + writes[execname()] = sum(arg2) + total_io[execname()] = sum(arg2) +} + +function humanread_digit(bytes) { + if (bytes > 1024*1024*1024) { + return bytes/1024/1024/1024 + } elseif (bytes > 1024*1024) { + return bytes/1024/1024 + } elseif (bytes > 1024) { + return bytes/1024 + } else { + return bytes + } +} + +function humanread_x(bytes) { + if (bytes > 1024*1024*1024) { + return " GiB" + } elseif (bytes > 1024*1024) { + return " MiB" + } elseif (bytes > 1024) { + return " KiB" + } else { + return " B" + } +} + +tick-1s { + ansi.clear_screen() + for (exec, count in pairs(total_io)) { + local readnum = reads[exec] + local writenum = writes[exec] + printf("%15s r: %12d%s w: %12d%s\n", exec, + humanread_digit(readnum), humanread_x(readnum), + humanread_digit(writenum), humanread_x(writenum)) + } + printf("\n") +} + diff --git a/drivers/staging/ktap/scripts/mem/kmalloc-top.kp b/drivers/staging/ktap/scripts/mem/kmalloc-top.kp new file mode 100644 index 000000000000..f18ed9fc64cf --- /dev/null +++ b/drivers/staging/ktap/scripts/mem/kmalloc-top.kp @@ -0,0 +1,17 @@ +#!/usr/bin/env ktap + +kmalloc_stack = {} + +trace kmem:kmalloc { + kmalloc_stack[backtrace()] += 1 +} + +tick-60s { + for (k, v in pairs(kmalloc_stack)) { + print(k) + printf("%d\n\n", v) + } + + exit() +} + diff --git a/drivers/staging/ktap/scripts/mem/kmem.kp b/drivers/staging/ktap/scripts/mem/kmem.kp new file mode 100644 index 000000000000..c6f2c99c54cd --- /dev/null +++ b/drivers/staging/ktap/scripts/mem/kmem.kp @@ -0,0 +1,30 @@ +#!/usr/bin/env ktap + +count1 = 0 +trace kmem:kmalloc { + count1 = count1 + 1 +} + +count2 = 0 +trace kmem:kfree { + count2 = count2 + 1 +} + +count3 = 0 +trace kmem:mm_page_alloc { + count3 = count3 + 1 +} + +count4 = 0 +trace kmem:mm_page_free { + count4 = count4 + 1 +} + +trace_end { + print("\n") + print("kmem:kmalloc:\t", count1) + print("kmem:kfree:\t", count2) + print("kmem:mm_page_alloc:", count3) + print("kmem:mm_page_free:", count4) + print("trace ending\n") +} diff --git a/drivers/staging/ktap/scripts/profiling/function_profiler.kp b/drivers/staging/ktap/scripts/profiling/function_profiler.kp new file mode 100644 index 000000000000..589017fe83b4 --- /dev/null +++ b/drivers/staging/ktap/scripts/profiling/function_profiler.kp @@ -0,0 +1,41 @@ +#!/usr/bin/env ktap + +#kernel function profile +#You can use this script to know what function is called frequently, +#without enable CONFIG_FUNCTION_PROFILER in kernel. + +s = aggr_table() + +trace ftrace:function { + s[arg1] = count() +} + +trace_end { + histogram(s) +} + +#sample output +#^C +# value ------------- Distribution ------------- count +# sub_preempt_count | @@@@@ 34904 +# add_preempt_count | @@@@@ 33435 +# nsecs_to_jiffies64 | @@@ 19919 +# irqtime_account_process_tick... | @ 9970 +# account_idle_time | @ 9880 +# _raw_spin_lock | 5100 +# _raw_spin_unlock | 5021 +# _raw_spin_unlock_irqrestore | 4235 +# _raw_spin_lock_irqsave | 4232 +# __rcu_read_lock | 3373 +# __rcu_read_unlock | 3373 +# lookup_address | 2392 +# pfn_range_is_mapped | 2384 +# update_cfs_rq_blocked_load | 1983 +# idle_cpu | 1808 +# ktime_get | 1394 +# _raw_spin_unlock_irq | 1270 +# _raw_spin_lock_irq | 1091 +# update_curr | 950 +# irqtime_account_irq | 950 +# ... | +# diff --git a/drivers/staging/ktap/scripts/profiling/stack_profile.kp b/drivers/staging/ktap/scripts/profiling/stack_profile.kp new file mode 100644 index 000000000000..97945602fcea --- /dev/null +++ b/drivers/staging/ktap/scripts/profiling/stack_profile.kp @@ -0,0 +1,26 @@ +#!/usr/bin/env ktap + +# This ktap script samples stacktrace of system per 10us, +# you can use generated output to make a flame graph. +# +# Flame Graphs: +# http://dtrace.org/blogs/brendan/2012/03/17/linux-kernel-performance-flame-graphs/ + +s = aggr_table() + +profile-10us { + s[backtrace()] = count() +} + +tick-60s { + exit() +} + +trace_end { + for (k, v in pairs(s)) { + print(k) + print(v) + print() + } +} + diff --git a/drivers/staging/ktap/scripts/schedule/sched_transition.kp b/drivers/staging/ktap/scripts/schedule/sched_transition.kp new file mode 100644 index 000000000000..eb54b09c3248 --- /dev/null +++ b/drivers/staging/ktap/scripts/schedule/sched_transition.kp @@ -0,0 +1,5 @@ +#!/usr/bin/env ktap + +trace sched:sched_switch { + printf("%s ... ", arg1) +} diff --git a/drivers/staging/ktap/scripts/schedule/schedtimes.kp b/drivers/staging/ktap/scripts/schedule/schedtimes.kp new file mode 100644 index 000000000000..acef904a2cae --- /dev/null +++ b/drivers/staging/ktap/scripts/schedule/schedtimes.kp @@ -0,0 +1,125 @@ +#!/usr/vin/env ktap + +#schedtimer.kp +#Initially inspired by Systemtap schedtimes.stp +#and more bugfree compare with Systemtap's version +# +#Note that the time value is associate with pid, not with execname strictly, +#sometime you will found there have sleep time for command "ls", the reason +#is that sleep time is belong to parent process bash, so clear on this. + +RUNNING = 0 +QUEUED = 1 +SLEEPING = 2 +DEAD = 64 + +run_time = {} +queued_time = {} +sleep_time = {} +io_wait_time = {} + +pid_state = {} +pid_names = {} +prev_timestamp = {} +io_wait = {} + +trace sched:sched_switch { + local prev_comm = arg1 + local prev_pid = arg2 + local prev_state = arg4 + local next_comm = arg5 + local next_pid = arg6 + local t = gettimeofday_us() + + if (pid_state[prev_pid] == nil) { + #do nothing + } elseif (pid_state[prev_pid] == RUNNING) { + run_time[prev_pid] += t - prev_timestamp[prev_pid] + } elseif (pid_state[prev_pid] == QUEUED) { + #found this: + #sched_wakeup comm=foo + #sched_switch prev_comm=foo + run_time[prev_pid] += t - prev_timestamp[prev_pid] + } + + pid_names[prev_pid] = prev_comm + prev_timestamp[prev_pid] = t + + if (prev_state == DEAD) { + pid_state[prev_pid] = DEAD + } elseif (prev_state > 0) { + if (in_iowait() == 1) { + io_wait[prev_pid] = 1 + } + pid_state[prev_pid] = SLEEPING + } elseif (prev_state == 0) { + pid_state[prev_pid] = QUEUED + } + + if (pid_state[next_pid] == nil) { + pid_state[next_pid] = RUNNING + } elseif (pid_state[next_pid] == QUEUED) { + queued_time[next_pid] += t - prev_timestamp[next_pid] + pid_state[next_pid] = RUNNING + } + + pid_names[next_pid] = next_comm + prev_timestamp[next_pid] = t +} + +trace sched:sched_wakeup, sched:sched_wakeup_new { + local comm = arg1 + local wakeup_pid = arg2 + local success = arg4 + local t = gettimeofday_us() + + if (pid_state[wakeup_pid] == nil) { + #do nothing + } elseif (pid_state[wakeup_pid] == SLEEPING) { + local durtion = t - prev_timestamp[wakeup_pid] + + sleep_time[wakeup_pid] += durtion + if (io_wait[wakeup_pid] == 1) { + io_wait_time[wakeup_pid] += durtion + io_wait[wakeup_pid] = 0 + } + } elseif (pid_state[wakeup_pid] == RUNNING) { + return + } + + pid_names[wakeup_pid] = comm + prev_timestamp[wakeup_pid] = t + pid_state[wakeup_pid] = QUEUED +} + +trace_end { + local t = gettimeofday_us() + + for (pid, state in pairs(pid_state)) { + local durtion = t - prev_timestamp[pid] + if (state == SLEEPING) { + sleep_time[pid] += durtion + } elseif (state == QUEUED) { + queued_time[pid] += durtion + } elseif (state == RUNNING) { + run_time[pid] += durtion + } + } + + printf ("%16s: %6s %10s %10s %10s %10s %10s\n\n", + "execname", "pid", "run(us)", "sleep(us)", "io_wait(us)", + "queued(us)", "total(us)") + + for (pid, time in pairs(run_time)) { + if (sleep_time[pid] == nil) { + sleep_time[pid] = 0 + } + if (queued_time[pid] == nil) { + queue_time[pid] = 0 + } + printf("%16s: %6d %10d %10d %10d %10d %10d\n", + pid_names[pid], pid, run_time[pid], sleep_time[pid], + io_wait_time[pid], queued_time[pid], + run_time[pid] + sleep_time[pid] + queued_time[pid]); + } +} diff --git a/drivers/staging/ktap/scripts/syscalls/errinfo.kp b/drivers/staging/ktap/scripts/syscalls/errinfo.kp new file mode 100644 index 000000000000..049031b3e374 --- /dev/null +++ b/drivers/staging/ktap/scripts/syscalls/errinfo.kp @@ -0,0 +1,145 @@ +#!/usr/bin/env ktap + +#errdesc get from include/uapi/asm-generic/errno*.h +errdesc = { + [1] = "Operation not permitted", #EPERM + [2] = "No such file or directory", #ENOENT + [3] = "No such process", #ESRCH + [4] = "Interrupted system call", #EINRT + [5] = "I/O error", #EIO + [6] = "No such device or address", #ENXIO + [7] = "Argument list too long", #E2BIG + [8] = "Exec format error", #ENOEXEC + [9] = "Bad file number", #EBADF + [10] = "No child processes", #ECHILD + [11] = "Try again", #EAGAIN + [12] = "Out of memory", #ENOMEM + [13] = "Permission denied", #EACCES + [14] = "Bad address", #EFAULT + [15] = "Block device required", #ENOTBLK + [16] = "Device or resource busy", #EBUSY + [17] = "File exists", #EEXIST + [18] = "Cross-device link", #EXDEV + [19] = "No such device", #ENODEV + [20] = "Not a directory", #ENOTDIR + [21] = "Is a directory", #EISDIR + [22] = "Invalid argument", #EINVAL + [23] = "File table overflow", #ENFILE + [24] = "Too many open files", #EMFILE + [25] = "Not a typewriter", #ENOTTY + [26] = "Text file busy", #ETXTBSY + [27] = "File too large", #EFBIG + [28] = "No space left on device", #ENOSPC + [29] = "Illegal seek", #ESPIPE + [30] = "Read-only file system", #EROFS + [31] = "Too many links", #EMLINK + [32] = "Broken pipe", #EPIPE + [33] = "Math argument out of domain of func", #EDOM + [34] = "Math result not representable", #ERANGE + + [35] = "Resource deadlock would occur", #EDEADLK + [36] = "File name too long", #ENAMETOOLONG + [37] = "No record locks available", #ENOLCK + [38] = "Function not implemented", #ENOSYS + [39] = "Directory not empty", #ENOTEMPTY + [40] = "Too many symbolic links encountered", #ELOOP + [42] = "No message of desired type", #ENOMSG + [43] = "Identifier removed", #EIDRM + [44] = "Channel number out of range", #ECHRNG + [45] = "Level 2 not synchronized", #EL2NSYNC + [46] = "Level 3 halted", #EL3HLT + [47] = "Level 3 reset", #EL3RST + [48] = "Link number out of range", #ELNRNG + [49] = "Protocol driver not attached", #EUNATCH + [50] = "No CSI structure available", #ENOCSI + [51] = "Level 2 halted", #EL2HLT + [52] = "Invalid exchange", #EBADE + [53] = "Invalid request descriptor", #EBADR + [54] = "Exchange full", #EXFULL + [55] = "No anode", #ENOANO + [56] = "Invalid request code", #EBADRQC + [57] = "Invalid slot", #EBADSLT + + [59] = "Bad font file format", #EBFONT + [60] = "Device not a stream", #ENOSTR + [61] = "No data available", #ENODATA + [62] = "Timer expired", #ETIME + [63] = "Out of streams resources", #ENOSR + [64] = "Machine is not on the network", #ENONET + [65] = "Package not installed", #ENOPKG + [66] = "Object is remote", #EREMOTE + [67] = "Link has been severed", #ENOLINK + [68] = "Advertise error", #EADV + [69] = "Srmount error", #ESRMNT + [70] = "Communication error on send", #ECOMM + [71] = "Protocol error", #EPROTO + [72] = "Multihop attempted", #EMULTIHOP + [73] = "RFS specific error", #EDOTDOT + [74] = "Not a data message", #EBADMSG + [75] = "Value too large for defined data type", #EOVERFLOW + [76] = "Name not unique on network", #ENOTUNIQ + [77] = "File descriptor in bad state", #EBADFD + [78] = "Remote address changed", #EREMCHG + [79] = "Can not access a needed shared library", #ELIBACC + [80] = "Accessing a corrupted shared library", #ELIBBAD + [81] = ".lib section in a.out corrupted", #ELIBSCN + [82] = "Attempting to link in too many shared libraries", #ELIBMAX + [83] = "Cannot exec a shared library directly", #ELIBEXEC + [84] = "Illegal byte sequence", #EILSEQ + [85] = "Interrupted system call should be restarted", #ERESTART + [86] = "Streams pipe error", #ESTRPIPE + [87] = "Too many users", #EUSERS + [88] = "Socket operation on non-socket", #ENOTSOCK + [89] = "Destination address required", #EDESTADDRREQ + [90] = "Message too long", #EMSGSIZE + [91] = "Protocol wrong type for socket", #EPROTOTYPE + [92] = "Protocol not available", #ENOPROTOOPT + [93] = "Protocol not supported", #EPROTONOSUPPORT + [94] = "Socket type not supported", #ESOCKTNOSUPPORT + [95] = "Operation not supported on transport endpoint", #EOPNOTSUPP + [96] = "Protocol family not supported", #EPFNOSUPPORT + [97] = "Address family not supported by protocol", #EAFNOSUPPORT + [98] = "Address already in use", #EADDRINUSE + [99] = "Cannot assign requested address", #EADDRNOTAVAIL + [100] = "Network is down", #ENETDOWN + [101] = "Network is unreachable", #ENETUNREACH + [102] = "Network dropped connection because of reset", #ENETRESET + [103] = "Software caused connection abort", #ECONNABORTED + [104] = "Connection reset by peer", #ECONNRESET + [105] = "No buffer space available", #ENOBUFS + [106] = "Transport endpoint is already connected", #EISCONN + [107] = "Transport endpoint is not connected", #ENOTCONN + [108] = " Cannot send after transport endpoint shutdown", #ESHUTDOWN + [109] = "Too many references: cannot splice", #ETOOMANYREFS + [110] = "Connection timed out", #ETIMEDOUT + [111] = "Connection refused", #ECONNREFUSED + [112] = "Host is down", #EHOSTDOWN + [113] = "No route to host", #EHOSTUNREACH + [114] = "Operation already in progress", #EALREADY + [115] = "Operation now in progress", #EINPROGRESS + [116] = "Stale NFS file handle", #ESTALE + [117] = "Structure needs cleaning", #EUCLEAN + [118] = "Not a XENIX named type file", #ENOTNAM + [119] = "No XENIX semaphores available", #ENAVAIL + [120] = "Is a named type file", #EISNAM + [121] = "Remote I/O error", #EREMOTEIO + [122] = "Quota exceeded", #EDQUOT + [123] = "No medium found", #ENOMEDIUM + [124] = "Wrong medium type", #EMEDIUMTYPE + [125] = "Operation Canceled", #ECANCELED + [126] = "Required key not available", #ENOKEY + [127] = "Key has expired", #EKEYEXPIRED + [128] = "Key has been revoked", #EKEYREVOKED + [129] = "Key was rejected by service", #EKEYREJECTED + [130] = "Owner died", #EOWNERDEAD + [131] = "State not recoverable", #ENOTRECOVERABLE + +} + +trace syscalls:sys_exit_* { + if (arg2 < 0) { + local errno = -arg2 + printf("%-15s%-20s\t%d\t%-30s\n", + execname(), argname, errno, errdesc[errno]) + } +} diff --git a/drivers/staging/ktap/scripts/syscalls/sctop.kp b/drivers/staging/ktap/scripts/syscalls/sctop.kp new file mode 100644 index 000000000000..6df45cb98178 --- /dev/null +++ b/drivers/staging/ktap/scripts/syscalls/sctop.kp @@ -0,0 +1,14 @@ +#! /usr/bin/env ktap + +#this script is broken, fix it soon. +s = {} + +trace syscalls:sys_enter_* { + s[argname] += 1 +} + +tick-5s { + ansi.clear_screen() + histogram(s) + delete(s) +} diff --git a/drivers/staging/ktap/scripts/syscalls/syscalls.kp b/drivers/staging/ktap/scripts/syscalls/syscalls.kp new file mode 100644 index 000000000000..8bbaacad68ac --- /dev/null +++ b/drivers/staging/ktap/scripts/syscalls/syscalls.kp @@ -0,0 +1,6 @@ +#!/usr/bin/env ktap + +trace syscalls:* { + print(cpu(), pid(), execname(), argevent) +} + diff --git a/drivers/staging/ktap/scripts/syscalls/syscalls_count.kp b/drivers/staging/ktap/scripts/syscalls/syscalls_count.kp new file mode 100644 index 000000000000..363c6226e8a9 --- /dev/null +++ b/drivers/staging/ktap/scripts/syscalls/syscalls_count.kp @@ -0,0 +1,56 @@ +#!/usr/bin/env ktap + +s = aggr_table() + +trace syscalls:sys_enter_* { + s[argname] = count() +} + +trace_end { + histogram(s) +} + +print("Press Control-C to stop.") + +#Result: +# +#[root@jovi ktap]# ./ktap scripts/syscalls_histogram.kp +#^C +# value ------------- Distribution ------------- count +# sys_enter_rt_sigprocmask |@@@@@@ 326 +# sys_enter_read |@@@@@ 287 +# sys_enter_close |@@@@ 236 +# sys_enter_open |@@@@ 222 +# sys_enter_stat64 |@@ 132 +# sys_enter_select |@@ 123 +# sys_enter_rt_sigaction |@@ 107 +# sys_enter_poll |@ 72 +# sys_enter_write |@ 70 +# sys_enter_mmap_pgoff |@ 58 +# sys_enter_fstat64 | 41 +# sys_enter_nanosleep | 23 +# sys_enter_access | 20 +# sys_enter_mprotect | 18 +# sys_enter_geteuid | 17 +# sys_enter_getegid | 16 +# sys_enter_getuid | 16 +# sys_enter_getgid | 16 +# sys_enter_brk | 15 +# sys_enter_waitpid | 11 +# sys_enter_time | 10 +# sys_enter_ioctl | 9 +# sys_enter_munmap | 9 +# sys_enter_fcntl64 | 7 +# sys_enter_dup2 | 7 +# sys_enter_clone | 6 +# sys_enter_exit_group | 6 +# sys_enter_execve | 4 +# sys_enter_pipe | 3 +# sys_enter_gettimeofday | 3 +# sys_enter_getdents | 2 +# sys_enter_getgroups | 2 +# sys_enter_statfs64 | 2 +# sys_enter_lseek | 2 +# sys_enter_openat | 1 +# sys_enter_newuname | 1 + diff --git a/drivers/staging/ktap/scripts/syscalls/syscalls_count_by_proc.kp b/drivers/staging/ktap/scripts/syscalls/syscalls_count_by_proc.kp new file mode 100644 index 000000000000..7b7d722b893d --- /dev/null +++ b/drivers/staging/ktap/scripts/syscalls/syscalls_count_by_proc.kp @@ -0,0 +1,24 @@ +#!/usr/bin/env ktap + +s = aggr_table() + +trace syscalls:sys_enter_* { + s[execname()] = count() +} + +trace_end { + histogram(s) +} + +print("Press Control-C to stop.") + +#Result: +# +#[root@jovi ktap]# ./ktap scripts/syscalls_histogram2.kp +#^C +# value ------------- Distribution ------------- count +# sshd |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 196 +# iscsid |@@@@ 24 +# sendmail |@ 9 + + diff --git a/drivers/staging/ktap/scripts/tracepoints/eventcount.kp b/drivers/staging/ktap/scripts/tracepoints/eventcount.kp new file mode 100644 index 000000000000..9bc357fca56b --- /dev/null +++ b/drivers/staging/ktap/scripts/tracepoints/eventcount.kp @@ -0,0 +1,212 @@ +#!/usr/bin/env ktap + +# showing all tracepoints in histogram style + +s = {} + +trace *:* { + s[argname] += 1 +} + +trace_end { + histogram(s) +} + +print("Press Control-C to stop.") + +#Results: +#^C +# +# value ------------- Distribution ------------- count +# rcu_utilization |@@@@@ 225289 +# cpu_idle |@@@ 120168 +# sched_wakeup |@@ 91950 +# timer_cancel |@@ 91232 +# timer_start |@@ 91201 +# sched_stat_sleep |@@ 90981 +# timer_expire_exit |@@ 90634 +# timer_expire_entry |@@ 90625 +# hrtimer_cancel |@ 75411 +# hrtimer_start |@ 74946 +# softirq_raise |@ 63117 +# softirq_exit |@ 63109 +# softirq_entry |@ 63094 +# sched_switch |@ 62331 +# sched_stat_wait |@ 60491 +# hrtimer_expire_exit |@ 47538 +# hrtimer_expire_entry |@ 47530 +# sched_stat_runtime | 2780 +# kmem_cache_free | 2684 +# kmem_cache_alloc | 2415 +# kfree | 2288 +# sys_exit | 2145 +# sys_enter | 2145 +# sys_exit_rt_sigprocmask | 1000 +# sys_enter_rt_sigprocmask | 1000 +# timer_init | 912 +# sched_stat_blocked | 685 +# kmalloc | 667 +# workqueue_execute_end | 621 +# workqueue_execute_start | 621 +# sys_enter_select | 566 +# sys_exit_select | 566 +# sys_enter_read | 526 +# sys_exit_read | 526 +# mm_page_free | 478 +# mm_page_alloc | 427 +# mm_page_free_batched | 382 +# net_dev_queue | 296 +# net_dev_xmit | 296 +# consume_skb | 296 +# sys_exit_write | 290 +# sys_enter_write | 290 +# kfree_skb | 289 +# kmem_cache_alloc_node | 269 +# kmalloc_node | 263 +# sys_enter_close | 249 +# sys_exit_close | 249 +# hrtimer_init | 248 +# netif_receive_skb | 242 +# sys_enter_open | 237 +# sys_exit_open | 237 +# napi_poll | 226 +# sched_migrate_task | 207 +# sys_exit_poll | 173 +# sys_enter_poll | 173 +# workqueue_queue_work | 152 +# workqueue_activate_work | 152 +# sys_enter_stat64 | 133 +# sys_exit_stat64 | 133 +# sys_exit_rt_sigaction | 133 +# sys_enter_rt_sigaction | 133 +# irq_handler_entry | 125 +# irq_handler_exit | 125 +# mm_page_alloc_zone_locked | 99 +# sys_exit_mmap_pgoff | 66 +# sys_enter_mmap_pgoff | 66 +# sys_exit_fstat64 | 54 +# sys_enter_fstat64 | 54 +# sys_enter_nanosleep | 51 +# sys_exit_nanosleep | 51 +# block_bio_queue | 46 +# block_bio_remap | 46 +# block_bio_complete | 46 +# mix_pool_bytes | 44 +# mm_page_pcpu_drain | 31 +# sys_exit_time | 23 +# sys_enter_time | 23 +# sys_exit_access | 20 +# sys_enter_access | 20 +# mix_pool_bytes_nolock | 18 +# sys_enter_mprotect | 18 +# sys_exit_mprotect | 18 +# sys_enter_geteuid | 17 +# sys_exit_geteuid | 17 +# sys_enter_munmap | 17 +# sys_exit_munmap | 17 +# block_getrq | 16 +# sys_enter_getuid | 16 +# sys_enter_getgid | 16 +# sys_exit_getgid | 16 +# sys_exit_getuid | 16 +# block_rq_issue | 16 +# scsi_dispatch_cmd_start | 16 +# block_rq_complete | 16 +# scsi_dispatch_cmd_done | 16 +# sys_enter_getegid | 16 +# sys_exit_getegid | 16 +# block_rq_insert | 16 +# skb_copy_datagram_iovec | 15 +# sys_enter_brk | 15 +# sys_exit_brk | 15 +# credit_entropy_bits | 14 +# wbc_writepage | 14 +# sys_exit_clone | 12 +# block_touch_buffer | 12 +# sched_process_wait | 11 +# sys_enter_waitpid | 11 +# sys_exit_waitpid | 11 +# writeback_written | 10 +# writeback_start | 10 +# writeback_queue_io | 10 +# ext4_es_lookup_extent_enter | 9 +# sys_enter_ioctl | 9 +# sys_exit_ioctl | 9 +# ext4_ext_map_blocks_enter | 9 +# ext4_ext_map_blocks_exit | 9 +# ext4_es_lookup_extent_exit | 9 +# ext4_es_insert_extent | 9 +# ext4_ext_show_extent | 8 +# extract_entropy | 8 +#ext4_es_find_delayed_extent_exit | 8 +# ext4_es_find_delayed_extent_... | 8 +# writeback_pages_written | 7 +# sys_exit_dup2 | 7 +# sys_enter_dup2 | 7 +# signal_generate | 7 +# sys_enter_fcntl64 | 7 +# sys_exit_fcntl64 | 7 +# global_dirty_state | 7 +# writeback_dirty_inode_start | 7 +# block_bio_backmerge | 7 +# writeback_dirty_inode | 7 +# sched_wakeup_new | 6 +# sched_process_free | 6 +# sys_enter_exit_group | 6 +# task_newtask | 6 +# sys_enter_clone | 6 +# sched_process_fork | 6 +# sched_process_exit | 6 +# sys_exit_gettimeofday | 5 +# signal_deliver | 5 +# sys_enter_gettimeofday | 5 +# writeback_single_inode | 4 +# sys_enter_execve | 4 +# task_rename | 4 +# sched_process_exec | 4 +# block_dirty_buffer | 4 +# sys_exit_execve | 4 +# block_unplug | 4 +# sched_stat_iowait | 4 +# writeback_single_inode_start | 4 +# block_plug | 4 +# writeback_write_inode | 3 +# sys_enter_pipe | 3 +# writeback_dirty_page | 3 +# writeback_write_inode_start | 3 +# ext4_mark_inode_dirty | 3 +# ext4_journal_start | 3 +# sys_exit_pipe | 3 +# jbd2_drop_transaction | 2 +# jbd2_commit_locking | 2 +# jbd2_commit_flushing | 2 +# jbd2_handle_start | 2 +# jbd2_run_stats | 2 +# sys_exit_getdents | 2 +# jbd2_checkpoint_stats | 2 +# sys_enter_getgroups | 2 +# jbd2_start_commit | 2 +# jbd2_end_commit | 2 +# ext4_da_writepages | 2 +# jbd2_handle_stats | 2 +# sys_enter_statfs64 | 2 +# sys_exit_statfs64 | 2 +# sys_exit_getgroups | 2 +# sys_exit_lseek | 2 +# sys_enter_lseek | 2 +# sys_enter_getdents | 2 +# ext4_da_write_pages | 2 +# jbd2_commit_logging | 2 +# ext4_request_blocks | 1 +# sys_exit_openat | 1 +# ext4_discard_preallocations | 1 +# ext4_mballoc_alloc | 1 +# sys_enter_openat | 1 +# ext4_da_writepages_result | 1 +# ext4_allocate_blocks | 1 +# sys_enter_newuname | 1 +# ext4_da_update_reserve_space | 1 +# ext4_get_reserved_cluster_alloc | 1 +# sys_exit_newuname | 1 +# writeback_wake_thread | 1 + diff --git a/drivers/staging/ktap/scripts/tracepoints/eventcount_by_proc.kp b/drivers/staging/ktap/scripts/tracepoints/eventcount_by_proc.kp new file mode 100644 index 000000000000..8706f73d5b40 --- /dev/null +++ b/drivers/staging/ktap/scripts/tracepoints/eventcount_by_proc.kp @@ -0,0 +1,59 @@ +#!/usr/bin/env ktap + +# showing all tracepoints in histogram style + +s = aggr_table() + +trace *:* { + s[execname()] = count() +} + +trace_end { + histogram(s) +} + +print("Press Control-C to stop.") + +#Results: +#^C +# value ------------- Distribution ------------- count +# swapper/0 |@@@@@@@@@@@@ 354378 +# swapper/1 |@@@@@@@@@@ 284984 +# ps |@@@@ 115697 +# ksmtuned |@@@ 95857 +# iscsid |@@ 80008 +# awk |@ 30354 +# irqbalance | 16530 +# rcu_sched | 15892 +# sendmail | 14463 +# kworker/0:1 | 10540 +# kworker/u4:2 | 9250 +# kworker/1:2 | 7943 +# sleep | 7555 +# crond | 3911 +# ksoftirqd/0 | 3817 +# sshd | 2849 +# systemd-journal | 2209 +# migration/1 | 1601 +# migration/0 | 1350 +# dhclient | 1343 +# nm-dhcp-client. | 1208 +# ksoftirqd/1 | 1064 +# watchdog/1 | 966 +# watchdog/0 | 964 +# khugepaged | 776 +# dbus-daemon | 611 +# rpcbind | 607 +# gdbus | 529 +# NetworkManager | 399 +# jbd2/dm-1-8 | 378 +# modem-manager | 184 +# abrt-watch-log | 157 +# polkitd | 156 +# rs:main Q:Reg | 153 +# avahi-daemon | 151 +# rsyslogd | 102 +# systemd | 96 +# kworker/0:1H | 45 +# smartd | 30 + diff --git a/drivers/staging/ktap/scripts/tracepoints/tracepoints.kp b/drivers/staging/ktap/scripts/tracepoints/tracepoints.kp new file mode 100644 index 000000000000..5d088695bbf2 --- /dev/null +++ b/drivers/staging/ktap/scripts/tracepoints/tracepoints.kp @@ -0,0 +1,6 @@ +#!/usr/bin/env ktap + +trace *:* { + print(cpu(), pid(), execname(), argevent) +} + diff --git a/drivers/staging/ktap/scripts/userspace/uprobes-malloc.kp b/drivers/staging/ktap/scripts/userspace/uprobes-malloc.kp new file mode 100644 index 000000000000..14c172f8f327 --- /dev/null +++ b/drivers/staging/ktap/scripts/userspace/uprobes-malloc.kp @@ -0,0 +1,9 @@ +#!/usr/bin/env ktap + +trace probe:/lib/libc.so.6:0x000773c0 { + print("entry:", execname(), argevent) +} + +trace probe:/lib/libc.so.6:0x000773c0%return { + print("exit:", execname(), argevent) +} diff --git a/drivers/staging/ktap/test/aggr_table.kp b/drivers/staging/ktap/test/aggr_table.kp new file mode 100644 index 000000000000..985b634952c1 --- /dev/null +++ b/drivers/staging/ktap/test/aggr_table.kp @@ -0,0 +1,50 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#---------------------------------# + +s = aggr_table() + +s["count"] = count() +s["count"] = count() +s["count"] = count() + +s["max"] = max(1) +s["max"] = max(0) +s["max"] = max(100) + +s["min"] = min(50) +s["min"] = min(2) +s["min"] = min(100) + +s["sum"] = sum(10) +s["sum"] = sum(20) +s["sum"] = sum(30) + +s["avg"] = avg(10) +s["avg"] = avg(20) +s["avg"] = avg(30) + +if (s["count"] != 3) { + failed() +} + +if (s["max"] != 100) { + failed() +} + +if (s["min"] != 2) { + failed() +} + +if (s["sum"] != 60) { + failed() +} + +if (s["avg"] != 20) { + failed() +} diff --git a/drivers/staging/ktap/test/ansi.kp b/drivers/staging/ktap/test/ansi.kp new file mode 100644 index 000000000000..e8a27835ce75 --- /dev/null +++ b/drivers/staging/ktap/test/ansi.kp @@ -0,0 +1,20 @@ +#!/usr/bin/env ktap + +ansi.clear_screen() + +ansi.set_color(32) +printf("this line should be Green color\n") + +ansi.set_color(31) +printf("this line should be Red color\n") + +ansi.set_color2(34, 43) +printf("this line should be Blue color, with Yellow background\n") + +ansi.reset_color() +ansi.set_color3(34, 46, 4) +printf("this line should be Blue color, with Cyan background, underline single attribute\n") + +ansi.reset_color() +ansi.new_line() + diff --git a/drivers/staging/ktap/test/arg.kp b/drivers/staging/ktap/test/arg.kp new file mode 100644 index 000000000000..0cf16ebf3227 --- /dev/null +++ b/drivers/staging/ktap/test/arg.kp @@ -0,0 +1,24 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#-----------------------------------------# + +if (!arg[0]) { + failed() +} + +if (arg[1] != 1) { + failed() +} + +if (arg[2] != "testing") { + failed() +} + +if (arg[3] != "2 3 4") { + failed() +} diff --git a/drivers/staging/ktap/test/arith.kp b/drivers/staging/ktap/test/arith.kp new file mode 100644 index 000000000000..32880a140c69 --- /dev/null +++ b/drivers/staging/ktap/test/arith.kp @@ -0,0 +1,27 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#-----------------------------------------# + +a = 4 +b = 5 + +if ((a + b) != 9) { + failed() +} + +if ((a - b) != -1) { + failed() +} + +if ((a % b) != 4) { + failed() +} + +if ((a / b) != 0) { + failed() +} diff --git a/drivers/staging/ktap/test/bench/sembench.c b/drivers/staging/ktap/test/bench/sembench.c new file mode 100644 index 000000000000..08119341c91d --- /dev/null +++ b/drivers/staging/ktap/test/bench/sembench.c @@ -0,0 +1,556 @@ +/* + * copyright Oracle 2007. Licensed under GPLv2 + * To compile: gcc -Wall -o sembench sembench.c -lpthread + * + * usage: sembench -t thread count -w wakenum -r runtime -o op + * op can be: 0 (ipc sem) 1 (nanosleep) 2 (futexes) + * + * example: + * sembench -t 1024 -w 512 -r 60 -o 2 + * runs 1024 threads, waking up 512 at a time, running for 60 seconds using + * futex locking. + * + */ +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 199309 +#include <fcntl.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/sem.h> +#include <sys/ipc.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <pthread.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <sys/time.h> +#include <sys/syscall.h> +#include <errno.h> + +#define VERSION "0.2" + +/* futexes have been around since 2.5.something, but it still seems I + * need to make my own syscall. Sigh. + */ +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_FD 2 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +static inline int futex (int *uaddr, int op, int val, + const struct timespec *timeout, + int *uaddr2, int val3) +{ + return syscall(__NR_futex, uaddr, op, val, timeout, uaddr2, val3); +} + +static void smp_mb(void) +{ + __sync_synchronize(); +} + +static int all_done = 0; +static int timeout_test = 0; + +#define SEMS_PERID 250 + +struct sem_operations; + +struct lockinfo { + unsigned long id; + unsigned long index; + int data; + pthread_t tid; + struct lockinfo *next; + struct sem_operations *ops; + unsigned long ready; +}; + +struct sem_wakeup_info { + int wakeup_count; + struct sembuf sb[SEMS_PERID]; +}; + +struct sem_operations { + void (*wait)(struct lockinfo *l); + int (*wake)(struct sem_wakeup_info *wi, int num_semids, int num); + void (*setup)(struct sem_wakeup_info **wi, int num_semids); + void (*cleanup)(int num_semids); + char *name; +}; + +int *semid_lookup = NULL; + +pthread_mutex_t worklist_mutex = PTHREAD_MUTEX_INITIALIZER; +static unsigned long total_burns = 0; +static unsigned long min_burns = ~0UL; +static unsigned long max_burns = 0; + +/* currently running threads */ +static int thread_count = 0; + +struct lockinfo *worklist = NULL; +static int workers_started = 0; + +/* total threads started */ +static int num_threads = 2048; + +static void worklist_add(struct lockinfo *l) +{ + smp_mb(); + l->ready = 1; +} + +static struct lockinfo *worklist_rm(void) +{ + static int last_index = 0; + int i; + struct lockinfo *l; + + for (i = 0; i < num_threads; i++) { + int test = (last_index + i) % num_threads; + + l = worklist + test; + smp_mb(); + if (l->ready) { + l->ready = 0; + last_index = test; + return l; + } + } + return NULL; +} + +/* ipc semaphore post& wait */ +void wait_ipc_sem(struct lockinfo *l) +{ + struct sembuf sb; + int ret; + struct timespec *tvp = NULL; + struct timespec tv = { 0, 1 }; + + sb.sem_num = l->index; + sb.sem_flg = 0; + + sb.sem_op = -1; + l->data = 1; + + if (timeout_test && (l->id % 5) == 0) + tvp = &tv; + + worklist_add(l); + ret = semtimedop(semid_lookup[l->id], &sb, 1, tvp); + + while(l->data != 0 && tvp) { + struct timespec tv2 = { 0, 500 }; + nanosleep(&tv2, NULL); + } + + if (l->data != 0) { + if (tvp) + return; + fprintf(stderr, "wakeup without data update\n"); + exit(1); + } + if (ret) { + if (errno == EAGAIN && tvp) + return; + perror("semtimed op"); + exit(1); + } +} + +int ipc_wake_some(struct sem_wakeup_info *wi, int num_semids, int num) +{ + int i; + int ret; + struct lockinfo *l; + int found = 0; + + for (i = 0; i < num_semids; i++) { + wi[i].wakeup_count = 0; + } + while(num > 0) { + struct sembuf *sb; + l = worklist_rm(); + if (!l) + break; + if (l->data != 1) + fprintf(stderr, "warning, lockinfo data was %d\n", + l->data); + l->data = 0; + sb = wi[l->id].sb + wi[l->id].wakeup_count; + sb->sem_num = l->index; + sb->sem_op = 1; + sb->sem_flg = IPC_NOWAIT; + wi[l->id].wakeup_count++; + found++; + num--; + } + if (!found) + return 0; + for (i = 0; i < num_semids; i++) { + int wakeup_total; + int cur; + int offset = 0; + if (!wi[i].wakeup_count) + continue; + wakeup_total = wi[i].wakeup_count; + while(wakeup_total > 0) { + cur = wakeup_total > 64 ? 64 : wakeup_total; + ret = semtimedop(semid_lookup[i], wi[i].sb + offset, + cur, NULL); + if (ret) { + perror("semtimedop"); + exit(1); + } + offset += cur; + wakeup_total -= cur; + } + } + return found; +} + +void setup_ipc_sems(struct sem_wakeup_info **wi, int num_semids) +{ + int i; + *wi = malloc(sizeof(**wi) * num_semids); + semid_lookup = malloc(num_semids * sizeof(int)); + for(i = 0; i < num_semids; i++) { + semid_lookup[i] = semget(IPC_PRIVATE, SEMS_PERID, + IPC_CREAT | 0777); + if (semid_lookup[i] < 0) { + perror("semget"); + exit(1); + } + } + sleep(10); +} + +void cleanup_ipc_sems(int num) +{ + int i; + for (i = 0; i < num; i++) { + semctl(semid_lookup[i], 0, IPC_RMID); + } +} + +struct sem_operations ipc_sem_ops = { + .wait = wait_ipc_sem, + .wake = ipc_wake_some, + .setup = setup_ipc_sems, + .cleanup = cleanup_ipc_sems, + .name = "ipc sem operations", +}; + +/* futex post & wait */ +void wait_futex_sem(struct lockinfo *l) +{ + int ret; + l->data = 1; + worklist_add(l); + while(l->data == 1) { + ret = futex(&l->data, FUTEX_WAIT, 1, NULL, NULL, 0); + /* + if (ret && ret != EWOULDBLOCK) { + perror("futex wait"); + exit(1); + }*/ + } +} + +int futex_wake_some(struct sem_wakeup_info *wi, int num_semids, int num) +{ + int i; + int ret; + struct lockinfo *l; + int found = 0; + + for (i = 0; i < num; i++) { + l = worklist_rm(); + if (!l) + break; + if (l->data != 1) + fprintf(stderr, "warning, lockinfo data was %d\n", + l->data); + l->data = 0; + ret = futex(&l->data, FUTEX_WAKE, 1, NULL, NULL, 0); + if (ret < 0) { + perror("futex wake"); + exit(1); + } + found++; + } + return found; +} + +void setup_futex_sems(struct sem_wakeup_info **wi, int num_semids) +{ + return; +} + +void cleanup_futex_sems(int num) +{ + return; +} + +struct sem_operations futex_sem_ops = { + .wait = wait_futex_sem, + .wake = futex_wake_some, + .setup = setup_futex_sems, + .cleanup = cleanup_futex_sems, + .name = "futex sem operations", +}; + +/* nanosleep sems here */ +void wait_nanosleep_sem(struct lockinfo *l) +{ + int ret; + struct timespec tv = { 0, 1000000 }; + int count = 0; + + l->data = 1; + worklist_add(l); + while(l->data) { + ret = nanosleep(&tv, NULL); + if (ret) { + perror("nanosleep"); + exit(1); + } + count++; + } +} + +int nanosleep_wake_some(struct sem_wakeup_info *wi, int num_semids, int num) +{ + int i; + struct lockinfo *l; + + for (i = 0; i < num; i++) { + l = worklist_rm(); + if (!l) + break; + if (l->data != 1) + fprintf(stderr, "warning, lockinfo data was %d\n", + l->data); + l->data = 0; + } + return i; +} + +void setup_nanosleep_sems(struct sem_wakeup_info **wi, int num_semids) +{ + return; +} + +void cleanup_nanosleep_sems(int num) +{ + return; +} + +struct sem_operations nanosleep_sem_ops = { + .wait = wait_nanosleep_sem, + .wake = nanosleep_wake_some, + .setup = setup_nanosleep_sems, + .cleanup = cleanup_nanosleep_sems, + .name = "nano sleep sem operations", +}; + +void *worker(void *arg) +{ + struct lockinfo *l = (struct lockinfo *)arg; + int burn_count = 0; + pthread_t tid = pthread_self(); + size_t pagesize = getpagesize(); + char *buf = malloc(pagesize); + + if (!buf) { + perror("malloc"); + exit(1); + } + + l->tid = tid; + workers_started = 1; + smp_mb(); + + while(!all_done) { + l->ops->wait(l); + if (all_done) + break; + burn_count++; + } + pthread_mutex_lock(&worklist_mutex); + total_burns += burn_count; + if (burn_count < min_burns) + min_burns = burn_count; + if (burn_count > max_burns) + max_burns = burn_count; + thread_count--; + pthread_mutex_unlock(&worklist_mutex); + return (void *)0; +} + +void print_usage(void) +{ + printf("usage: sembench [-t threads] [-w wake incr] [-r runtime]"); + printf(" [-o num] (0=ipc, 1=nanosleep, 2=futex)\n"); + exit(1); +} + +#define NUM_OPERATIONS 3 +struct sem_operations *allops[NUM_OPERATIONS] = { &ipc_sem_ops, + &nanosleep_sem_ops, + &futex_sem_ops}; + +int main(int ac, char **av) { + int ret; + int i; + int semid = 0; + int sem_num = 0; + int burn_count = 0; + struct sem_wakeup_info *wi = NULL; + struct timeval start; + struct timeval now; + int num_semids = 0; + int wake_num = 256; + int run_secs = 30; + int pagesize = getpagesize(); + char *buf = malloc(pagesize); + struct sem_operations *ops = allops[0]; + cpu_set_t cpu_mask; + cpu_set_t target_mask; + int target_cpu = 0; + int max_cpu = -1; + + if (!buf) { + perror("malloc"); + exit(1); + } + for (i = 1; i < ac; i++) { + if (strcmp(av[i], "-t") == 0) { + if (i == ac -1) + print_usage(); + num_threads = atoi(av[i+1]); + i++; + } else if (strcmp(av[i], "-w") == 0) { + if (i == ac -1) + print_usage(); + wake_num = atoi(av[i+1]); + i++; + } else if (strcmp(av[i], "-r") == 0) { + if (i == ac -1) + print_usage(); + run_secs = atoi(av[i+1]); + i++; + } else if (strcmp(av[i], "-o") == 0) { + int index; + if (i == ac -1) + print_usage(); + index = atoi(av[i+1]); + if (index >= NUM_OPERATIONS) { + fprintf(stderr, "invalid operations %d\n", + index); + exit(1); + } + ops = allops[index]; + i++; + } else if (strcmp(av[i], "-T") == 0) { + timeout_test = 1; + } else if (strcmp(av[i], "-h") == 0) { + print_usage(); + } + } + num_semids = (num_threads + SEMS_PERID - 1) / SEMS_PERID; + ops->setup(&wi, num_semids); + + ret = sched_getaffinity(0, sizeof(cpu_set_t), &cpu_mask); + if (ret) { + perror("sched_getaffinity"); + exit(1); + } + for (i = 0; i < CPU_SETSIZE; i++) + if (CPU_ISSET(i, &cpu_mask)) + max_cpu = i; + if (max_cpu == -1) { + fprintf(stderr, "sched_getaffinity returned empty mask\n"); + exit(1); + } + + CPU_ZERO(&target_mask); + + worklist = malloc(sizeof(*worklist) * num_threads); + memset(worklist, 0, sizeof(*worklist) * num_threads); + + for (i = 0; i < num_threads; i++) { + struct lockinfo *l; + pthread_t tid; + thread_count++; + l = worklist + i; + if (!l) { + perror("malloc"); + exit(1); + } + l->id = semid; + l->index = sem_num++; + l->ops = ops; + if (sem_num >= SEMS_PERID) { + semid++; + sem_num = 0; + } + ret = pthread_create(&tid, NULL, worker, (void *)l); + if (ret) { + perror("pthread_create"); + exit(1); + } + + while (!CPU_ISSET(target_cpu, &cpu_mask)) { + target_cpu++; + if (target_cpu > max_cpu) + target_cpu = 0; + } + CPU_SET(target_cpu, &target_mask); + ret = pthread_setaffinity_np(tid, sizeof(cpu_set_t), + &target_mask); + CPU_CLR(target_cpu, &target_mask); + target_cpu++; + + ret = pthread_detach(tid); + if (ret) { + perror("pthread_detach"); + exit(1); + } + } + while(!workers_started) { + smp_mb(); + usleep(200); + } + gettimeofday(&start, NULL); + fprintf(stderr, "main loop going\n"); + while(1) { + ops->wake(wi, num_semids, wake_num); + burn_count++; + gettimeofday(&now, NULL); + if (now.tv_sec - start.tv_sec >= run_secs) + break; + } + fprintf(stderr, "all done\n"); + all_done = 1; + while(thread_count > 0) { + ops->wake(wi, num_semids, wake_num); + usleep(200); + } + printf("%d threads, waking %d at a time\n", num_threads, wake_num); + printf("using %s\n", ops->name); + printf("main thread burns: %d\n", burn_count); + printf("worker burn count total %lu min %lu max %lu avg %lu\n", + total_burns, min_burns, max_burns, total_burns / num_threads); + printf("run time %d seconds %lu worker burns per second\n", + (int)(now.tv_sec - start.tv_sec), + total_burns / (now.tv_sec - start.tv_sec)); + ops->cleanup(num_semids); + return 0; +} + diff --git a/drivers/staging/ktap/test/bench/test.sh b/drivers/staging/ktap/test/bench/test.sh new file mode 100644 index 000000000000..9f77969b6f2b --- /dev/null +++ b/drivers/staging/ktap/test/bench/test.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +gcc -o sembench sembench.c -O2 -lpthread + +COMMAND="./sembench -t 200 -w 20 -r 30 -o 2" + +echo -e "\n\t\tPass 1 without tracing" +$COMMAND +echo -e "\n\t\tPass 2 without tracing" +$COMMAND +echo -e "\n\t\tPass 3 without tracing" +$COMMAND + +echo "" + +KTAP_ONE_LINER="trace syscalls:sys_*_futex {}" + +echo -e "\n\t\tPass 1 with tracing" +../../ktap -e "$KTAP_ONE_LINER" -- $COMMAND +echo -e "\n\t\tPass 2 with tracing" +../../ktap -e "$KTAP_ONE_LINER" -- $COMMAND +echo -e "\n\t\tPass 3 with tracing" +../../ktap -e "$KTAP_ONE_LINER" -- $COMMAND + +rm -rf ./sembench diff --git a/drivers/staging/ktap/test/concat.kp b/drivers/staging/ktap/test/concat.kp new file mode 100644 index 000000000000..be77bb70ea8e --- /dev/null +++ b/drivers/staging/ktap/test/concat.kp @@ -0,0 +1,15 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#----------------------------------------# + +a = "123" +b = "456" + +if (a..b != "123456") { + failed() +} diff --git a/drivers/staging/ktap/test/count.kp b/drivers/staging/ktap/test/count.kp new file mode 100644 index 000000000000..26f962c227a4 --- /dev/null +++ b/drivers/staging/ktap/test/count.kp @@ -0,0 +1,20 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#---------------------------------------# + +t = {} + +t["key"] += 1 +if (t["key"] != 1) { + failed() +} + +t["key"] += 1 +if (t["key"] != 2) { + failed() +} diff --git a/drivers/staging/ktap/test/fibonacci.kp b/drivers/staging/ktap/test/fibonacci.kp new file mode 100644 index 000000000000..7e141da0de42 --- /dev/null +++ b/drivers/staging/ktap/test/fibonacci.kp @@ -0,0 +1,36 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#---------------fibonacci---------------- + + +#regular recursive fibonacci +function fib(n) { + if (n < 2) { + return n + } + return fib(n-1) + fib(n-2) +} + +if (fib(20) != 6765) { + failed() +} + +#tail recursive fibonacci +function fib(n) { + f = function (iter, res, next) { + if (iter == 0) { + return res; + } + return f(iter-1, next, res+next) + } + return f(n, 0, 1) +} + +if (fib(20) != 6765) { + failed() +} diff --git a/drivers/staging/ktap/test/function.kp b/drivers/staging/ktap/test/function.kp new file mode 100644 index 000000000000..bfbff2614104 --- /dev/null +++ b/drivers/staging/ktap/test/function.kp @@ -0,0 +1,88 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +### basic function call ### +function f1(a, b) { + return a + b +} + +if (f1(2, 3) != 5) { + failed(); +} + +### return string ### +function f2() { + return "function return" +} + +if (f2() != "function return") { + failed(); +} + +### mutli-value return ### +function f3(a, b) { + return a+b, a-b; +} + +c, d = f3(2, 3); +if(c != 5 || d != -1) { + failed(); +} + + +### closure testing ### +function f4() { + f5 = function(a, b) { + return a * b + } + return f5 +} + +local f = f4() +if (f(9, 9) != 81) { + failed(); +} + +### closure with lexcial variable ### +# issue: variable cannot be local +i = 1 +function f6() { + i = 5 + f7 = function(a, b) { + return a * b + i + } + return f7 +} + +f = f6() +if (f(9, 9) != 81 + i) { + failed(); +} + +i = 6 +if (f(9, 9) != 81 + i) { + failed(); +} + +### tail call +### stack should not overflow in tail call mechanism +a = 0 +function f8(i) { + if (i == 1000000) { + a = 1000000 + return + } + # must add return here, otherwise stack overflow + return f8(i+1) +} + +f8(0) +if (a != 1000000) { + failed(); +} + + diff --git a/drivers/staging/ktap/test/if.kp b/drivers/staging/ktap/test/if.kp new file mode 100644 index 000000000000..3122084af5ee --- /dev/null +++ b/drivers/staging/ktap/test/if.kp @@ -0,0 +1,24 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#-----------------------------------------# + +if (false) { + failed() +} + +if (nil) { + failed() +} + +# ktap only think false and nil is "real false", number 0 is true +# it's same as lua +# Might change it in future, to make similar with C +if (0) { + #failed() +} + diff --git a/drivers/staging/ktap/test/kprobe.kp b/drivers/staging/ktap/test/kprobe.kp new file mode 100644 index 000000000000..022d4a70b31f --- /dev/null +++ b/drivers/staging/ktap/test/kprobe.kp @@ -0,0 +1,14 @@ +#!/usr/bin/env ktap + +n = 0 +trace probe:schedule { + n = n + 1 +} + +tick-1s { + if (n == 0) { + printf("failed\n"); + } + exit() +} + diff --git a/drivers/staging/ktap/test/kretprobe.kp b/drivers/staging/ktap/test/kretprobe.kp new file mode 100644 index 000000000000..e311e84c292f --- /dev/null +++ b/drivers/staging/ktap/test/kretprobe.kp @@ -0,0 +1,14 @@ +#!/usr/bin/env ktap + +n = 0 +trace probe:__schedule%return { + n = n + 1 +} + +tick-1s { + if (n == 0) { + printf("failed\n"); + } + exit() +} + diff --git a/drivers/staging/ktap/test/len.kp b/drivers/staging/ktap/test/len.kp new file mode 100644 index 000000000000..697d91553ba9 --- /dev/null +++ b/drivers/staging/ktap/test/len.kp @@ -0,0 +1,25 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#-----------------------------------------# + +a = "123456789" + +if (len(a) != 9) { + failed() +} + +b = {} +b[0] = 0 +b[1] = 1 +b["keys"] = "values" + +if (len(b) != 3) { + failed() +} + + diff --git a/drivers/staging/ktap/test/looping.kp b/drivers/staging/ktap/test/looping.kp new file mode 100644 index 000000000000..fe48051a29c2 --- /dev/null +++ b/drivers/staging/ktap/test/looping.kp @@ -0,0 +1,40 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +### basic while-loop testing +a = 1 +while (a < 1000) { + a = a + 1 +} + +if (a != 1000) { + failed() +} + +### break testing +### Note that ktap don't have continue keyword +a = 1 +while (a < 1000) { + if (a == 10) { + break + } + a = a + 1 +} + +if (a != 10) { + failed() +} + +### for-loop testing +b=0 +for (c = 0, 1000, 1) { + b = b + 1 +} + +if (b != 1001) { + failed() +} diff --git a/drivers/staging/ktap/test/pairs.kp b/drivers/staging/ktap/test/pairs.kp new file mode 100644 index 000000000000..cdf3825951dd --- /dev/null +++ b/drivers/staging/ktap/test/pairs.kp @@ -0,0 +1,45 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#-----------------------------------------# + +t = {} +t[1] = 101 +t[2] = 102 +t[3] = 103 +t["key_1"] = "value_1" +t["key_2"] = "value_2" +t["key_3"] = "value_3" + +local n = 0 + +for (k, v in pairs(t)) { + n = n + 1 + + if (k == 1 && v != 101) { + failed() + } + if (k == 2 && v != 102) { + failed() + } + if (k == 3 && v != 103) { + failed() + } + if (k == "key_1" && v != "value_1") { + failed() + } + if (k == "key_2" && v != "value_2") { + failed() + } + if (k == "key_3" && v != "value_3") { + failed() + } +} + +if (n != len(t)) { + failed() +} diff --git a/drivers/staging/ktap/test/run_test.sh b/drivers/staging/ktap/test/run_test.sh new file mode 100644 index 000000000000..b98af2659123 --- /dev/null +++ b/drivers/staging/ktap/test/run_test.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +rmmod ktapvm > /dev/null 2>&1 +insmod ../ktapvm.ko +if test $? -ne 0; then + echo "Cannot insmod ../ktapvm.ko" + exit -1 +fi + +KTAP=../ktap +function ktaprun { + echo "$KTAP $@" + $KTAP $@ +} + + + +####################################################### +# Use $ktap directly if the arguments contains strings +$KTAP arg.kp 1 testing "2 3 4" +$KTAP -e 'print("one-liner testing")' +$KTAP -e 'exit()' +$KTAP -o /dev/null -e 'trace syscalls:* { print(argevent) }' \ + -- ls > /devnull + +$KTAP -o /dev/null -e 'trace syscalls:* { print(argevent) }' \ + -- $KTAP -e 'while (1) {}' + +ktaprun arith.kp +ktaprun concat.kp +ktaprun count.kp +ktaprun fibonacci.kp +ktaprun function.kp +ktaprun if.kp +ktaprun kprobe.kp +ktaprun kretprobe.kp +ktaprun len.kp +ktaprun looping.kp +ktaprun pairs.kp +ktaprun table.kp +ktaprun aggr_table.kp +ktaprun timer.kp +ktaprun tracepoint.kp +ktaprun -o /dev/null zerodivide.kp +ktaprun ansi.kp + +echo "testing kill deadloop ktap script" +$KTAP -e 'while (1) {}' & +pkill ktap +sleep 1 + +##################################################### +rmmod ktapvm +if test $? -ne 0; then + echo "Error in rmmod ../ktapvm.ko, leak module refcount?" + exit -1 +fi + diff --git a/drivers/staging/ktap/test/table.kp b/drivers/staging/ktap/test/table.kp new file mode 100644 index 000000000000..1f6d6e43302f --- /dev/null +++ b/drivers/staging/ktap/test/table.kp @@ -0,0 +1,71 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +### table testing ### +x = {} +x[1] = "1" +if (x[1] != "1") { + failed() +} + +x[1] = 22222222222222222222222222222222222222222 +if (x[1] != 22222222222222222222222222222222222222222) { + failed() +} + +x[1] = "jovi" +if (x[1] != "jovi") { + failed() +} + +x[11111111111111111111111111111111] = "jovi" +if (x[11111111111111111111111111111111] != "jovi") { + failed() +} + +x["jovi"] = 1 +if (x["jovi"] != 1) { + failed() +} + +x["long string....................................."] = 1 +if (x["long string....................................."] != 1) { + failed() +} + +# issue: subx must declare firstly, otherwise kernel will oops +subx = {} +subx["test"] = "this is test" +x["test"] = subx +if (x["test"]["test"] != "this is test") { + failed() +} + +tbl = {} +i = 1 +while (i < 100000) { + tbl[i] = i + i = i + 1 +} + +i = 1 +while (i < 100000) { + if (tbl[i] != i) { + failed() + } + i = i + 1 +} + +#### table initization +days = {"Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"} + +if (days[2] != "Monday") { + failed() +} + + diff --git a/drivers/staging/ktap/test/timer.kp b/drivers/staging/ktap/test/timer.kp new file mode 100644 index 000000000000..02e8a61da664 --- /dev/null +++ b/drivers/staging/ktap/test/timer.kp @@ -0,0 +1,28 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#---------------------------------------# + +n1 = 0 +n2 = 0 + +tick-1s { + n1 = n1 + 1 +} + +tick-1s { + n2 = n2 + 1 +} + +tick-4s { + if (n1 == 0 || n2 == 0) { + failed() + } + exit() +} + + diff --git a/drivers/staging/ktap/test/tracepoint.kp b/drivers/staging/ktap/test/tracepoint.kp new file mode 100644 index 000000000000..fb036e675a75 --- /dev/null +++ b/drivers/staging/ktap/test/tracepoint.kp @@ -0,0 +1,22 @@ +#!/usr/bin/env ktap + +function failed() { + printf("failed\n"); + exit(-1); +} + +#----------------------------------------# + +n = 0 + +trace sched:* { + n = n + 1 +} + +tick-1s { + if (n == 0) { + failed() + } + exit() +} + diff --git a/drivers/staging/ktap/test/zerodivide.kp b/drivers/staging/ktap/test/zerodivide.kp new file mode 100644 index 000000000000..abb1eae4fdab --- /dev/null +++ b/drivers/staging/ktap/test/zerodivide.kp @@ -0,0 +1,5 @@ +#!/usr/bin/env ktap + +a = 1/0 +#should not go here +printf("Failed\n") diff --git a/drivers/staging/ktap/userspace/code.c b/drivers/staging/ktap/userspace/code.c new file mode 100644 index 000000000000..1427fd518dec --- /dev/null +++ b/drivers/staging/ktap/userspace/code.c @@ -0,0 +1,968 @@ +/* + * code.c - Code generator for ktap + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../include/ktap_types.h" +#include "../include/ktap_opcodes.h" +#include "ktapc.h" + + +#define hasjumps(e) ((e)->t != (e)->f) + +void codegen_patchtohere (ktap_funcstate *fs, int list); + +static int isnumeral(ktap_expdesc *e) +{ + return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); +} + +void codegen_nil(ktap_funcstate *fs, int from, int n) +{ + ktap_instruction *previous; + int l = from + n - 1; /* last register to set nil */ + + if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pl = pfrom + GETARG_B(*previous); + + if ((pfrom <= from && from <= pl + 1) || + (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ + if (pfrom < from) + from = pfrom; /* from = min(from, pfrom) */ + if (pl > l) + l = pl; /* l = max(l, pl) */ + SETARG_A(*previous, from); + SETARG_B(*previous, l - from); + return; + } + } /* else go through */ + } + codegen_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ +} + +int codegen_jump(ktap_funcstate *fs) +{ + int jpc = fs->jpc; /* save list of jumps to here */ + int j; + + fs->jpc = NO_JUMP; + j = codegen_codeAsBx(fs, OP_JMP, 0, NO_JUMP); + codegen_concat(fs, &j, jpc); /* keep them on hold */ + return j; +} + +void codegen_ret(ktap_funcstate *fs, int first, int nret) +{ + codegen_codeABC(fs, OP_RETURN, first, nret+1, 0); +} + +static int condjump(ktap_funcstate *fs, OpCode op, int A, int B, int C) +{ + codegen_codeABC(fs, op, A, B, C); + return codegen_jump(fs); +} + +static void fixjump(ktap_funcstate *fs, int pc, int dest) +{ + ktap_instruction *jmp = &fs->f->code[pc]; + int offset = dest-(pc+1); + + ktap_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + lex_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); +} + +/* + * returns current `pc' and marks it as a jump target (to avoid wrong + * optimizations with consecutive instructions not in the same basic block). + */ +int codegen_getlabel(ktap_funcstate *fs) +{ + fs->lasttarget = fs->pc; + return fs->pc; +} + +static int getjump(ktap_funcstate *fs, int pc) +{ + int offset = GETARG_sBx(fs->f->code[pc]); + + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + +static ktap_instruction *getjumpcontrol(ktap_funcstate *fs, int pc) +{ + ktap_instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi-1; + else + return pi; +} + +/* + * check whether list has any jump that do not produce a value + * (or produce an inverted value) + */ +static int need_value(ktap_funcstate *fs, int list) +{ + for (; list != NO_JUMP; list = getjump(fs, list)) { + ktap_instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) + return 1; + } + return 0; /* not found */ +} + +static int patchtestreg(ktap_funcstate *fs, int node, int reg) +{ + ktap_instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else /* no register to put value or register already has the value */ + *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); + + return 1; +} + +static void removevalues(ktap_funcstate *fs, int list) +{ + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); +} + +static void patchlistaux(ktap_funcstate *fs, int list, int vtarget, int reg, + int dtarget) +{ + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } +} + +static void dischargejpc(ktap_funcstate *fs) +{ + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); + fs->jpc = NO_JUMP; +} + +void codegen_patchlist(ktap_funcstate *fs, int list, int target) +{ + if (target == fs->pc) + codegen_patchtohere(fs, list); + else { + ktap_assert(target < fs->pc); + patchlistaux(fs, list, target, NO_REG, target); + } +} + +void codegen_patchclose(ktap_funcstate *fs, int list, int level) +{ + level++; /* argument is +1 to reserve 0 as non-op */ + while (list != NO_JUMP) { + int next = getjump(fs, list); + ktap_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && + (GETARG_A(fs->f->code[list]) == 0 || + GETARG_A(fs->f->code[list]) >= level)); + SETARG_A(fs->f->code[list], level); + list = next; + } +} + +void codegen_patchtohere(ktap_funcstate *fs, int list) +{ + codegen_getlabel(fs); + codegen_concat(fs, &fs->jpc, list); +} + +void codegen_concat(ktap_funcstate *fs, int *l1, int l2) +{ + if (l2 == NO_JUMP) + return; + else if (*l1 == NO_JUMP) + *l1 = l2; + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); + } +} + +static int codegen_code(ktap_funcstate *fs, ktap_instruction i) +{ + ktap_proto *f = fs->f; + + dischargejpc(fs); /* `pc' will change */ + + /* put new instruction in code array */ + ktapc_growvector(f->code, fs->pc, f->sizecode, ktap_instruction, + MAX_INT, "opcodes"); + f->code[fs->pc] = i; + + /* save corresponding line information */ + ktapc_growvector(f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "opcodes"); + f->lineinfo[fs->pc] = fs->ls->lastline; + return fs->pc++; +} + +int codegen_codeABC(ktap_funcstate *fs, OpCode o, int a, int b, int c) +{ + ktap_assert(getOpMode(o) == iABC); + //ktap_assert(getBMode(o) != OpArgN || b == 0); + //ktap_assert(getCMode(o) != OpArgN || c == 0); + //ktap_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); + return codegen_code(fs, CREATE_ABC(o, a, b, c)); +} + +int codegen_codeABx(ktap_funcstate *fs, OpCode o, int a, unsigned int bc) +{ + ktap_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + ktap_assert(getCMode(o) == OpArgN); + ktap_assert(a <= MAXARG_A && bc <= MAXARG_Bx); + return codegen_code(fs, CREATE_ABx(o, a, bc)); +} + +static int codeextraarg(ktap_funcstate *fs, int a) +{ + ktap_assert(a <= MAXARG_Ax); + return codegen_code(fs, CREATE_Ax(OP_EXTRAARG, a)); +} + +int codegen_codek(ktap_funcstate *fs, int reg, int k) +{ + if (k <= MAXARG_Bx) + return codegen_codeABx(fs, OP_LOADK, reg, k); + else { + int p = codegen_codeABx(fs, OP_LOADKX, reg, 0); + codeextraarg(fs, k); + return p; + } +} + +void codegen_checkstack(ktap_funcstate *fs, int n) +{ + int newstack = fs->freereg + n; + + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXSTACK) + lex_syntaxerror(fs->ls, "function or expression too complex"); + fs->f->maxstacksize = (u8)(newstack); + } +} + +void codegen_reserveregs(ktap_funcstate *fs, int n) +{ + codegen_checkstack(fs, n); + fs->freereg += n; +} + +static void freereg(ktap_funcstate *fs, int reg) +{ + if (!ISK(reg) && reg >= fs->nactvar) { + fs->freereg--; + ktap_assert(reg == fs->freereg); + } +} + +static void freeexp(ktap_funcstate *fs, ktap_expdesc *e) +{ + if (e->k == VNONRELOC) + freereg(fs, e->u.info); +} + +static int addk(ktap_funcstate *fs, ktap_value *key, ktap_value *v) +{ + const ktap_value *idx = ktapc_table_get(fs->h, key); + ktap_proto *f = fs->f; + ktap_value kn; + int k, oldsize; + + if (ttisnumber(idx)) { + ktap_number n = nvalue(idx); + ktap_number2int(k, n); + if (ktapc_equalobj(&f->k[k], v)) + return k; + /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); + go through and create a new entry for this value */ + } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = fs->nk; + + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setnvalue(&kn, (ktap_number)k); + ktapc_table_setvalue(fs->h, key, &kn); + ktapc_growvector(f->k, k, f->sizek, ktap_value, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) + setnilvalue(&f->k[oldsize++]); + setobj(&f->k[k], v); + fs->nk++; + return k; +} + +int codegen_stringK(ktap_funcstate *fs, ktap_string *s) +{ + ktap_value o; + + setsvalue(&o, s); + return addk(fs, &o, &o); +} + +int codegen_numberK(ktap_funcstate *fs, ktap_number r) +{ + int n; + ktap_value o, s; + + setnvalue(&o, r); + if (r == 0 || ktap_numisnan(NULL, r)) { /* handle -0 and NaN */ + /* use raw representation as key to avoid numeric problems */ + setsvalue(&s, ktapc_ts_newlstr((char *)&r, sizeof(r))); + // incr_top(L); + n = addk(fs, &s, &o); + // L->top--; + } else + n = addk(fs, &o, &o); /* regular case */ + return n; +} + +static int boolK(ktap_funcstate *fs, int b) +{ + ktap_value o; + setbvalue(&o, b); + return addk(fs, &o, &o); +} + +static int nilK(ktap_funcstate *fs) +{ + ktap_value k, v; + setnilvalue(&v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(&k, fs->h); + return addk(fs, &k, &v); +} + +void codegen_setreturns(ktap_funcstate *fs, ktap_expdesc *e, int nresults) +{ + if (e->k == VCALL) { /* expression is an open function call? */ + SETARG_C(getcode(fs, e), nresults+1); + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), nresults+1); + SETARG_A(getcode(fs, e), fs->freereg); + codegen_reserveregs(fs, 1); + } +} + +void codegen_setoneret(ktap_funcstate *fs, ktap_expdesc *e) +{ + if (e->k == VCALL) { /* expression is an open function call? */ + e->k = VNONRELOC; + e->u.info = GETARG_A(getcode(fs, e)); + } else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), 2); + e->k = VRELOCABLE; /* can relocate its simple result */ + } +} + +void codegen_dischargevars(ktap_funcstate *fs, ktap_expdesc *e) +{ + switch (e->k) { + case VLOCAL: { + e->k = VNONRELOC; + break; + } + case VUPVAL: { + e->u.info = codegen_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + case VINDEXED: { + OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ + freereg(fs, e->u.ind.idx); + if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ + freereg(fs, e->u.ind.t); + op = OP_GETTABLE; + } + e->u.info = codegen_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOCABLE; + break; + } + case VVARARG: + case VCALL: { + codegen_setoneret(fs, e); + break; + } + default: + break; /* there is one value available (somewhere) */ + } +} + +static int code_label(ktap_funcstate *fs, int A, int b, int jump) +{ + codegen_getlabel(fs); /* those instructions may be jump targets */ + return codegen_codeABC(fs, OP_LOADBOOL, A, b, jump); +} + +static void discharge2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg) +{ + codegen_dischargevars(fs, e); + switch (e->k) { + case VNIL: { + codegen_nil(fs, reg, 1); + break; + } + case VFALSE: case VTRUE: { + codegen_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); + break; + } + case VEVENT: + codegen_codeABC(fs, OP_EVENT, reg, 0, 0); + break; + case VEVENTNAME: + codegen_codeABC(fs, OP_EVENTNAME, reg, 0, 0); + break; + case VEVENTARG: + codegen_codeABC(fs, OP_EVENTARG, reg, e->u.info, 0); + break; + case VK: { + codegen_codek(fs, reg, e->u.info); + break; + } + case VKNUM: { + codegen_codek(fs, reg, codegen_numberK(fs, e->u.nval)); + break; + } + case VRELOCABLE: { + ktap_instruction *pc = &getcode(fs, e); + SETARG_A(*pc, reg); + break; + } + case VNONRELOC: { + if (reg != e->u.info) + codegen_codeABC(fs, OP_MOVE, reg, e->u.info, 0); + break; + } + default: + ktap_assert(e->k == VVOID || e->k == VJMP); + return; /* nothing to do... */ + } + + e->u.info = reg; + e->k = VNONRELOC; +} + +static void discharge2anyreg(ktap_funcstate *fs, ktap_expdesc *e) +{ + if (e->k != VNONRELOC) { + codegen_reserveregs(fs, 1); + discharge2reg(fs, e, fs->freereg-1); + } +} + +static void exp2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg) +{ + discharge2reg(fs, e, reg); + if (e->k == VJMP) + codegen_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + + if (need_value(fs, e->t) || need_value(fs, e->f)) { + int fj = (e->k == VJMP) ? NO_JUMP : codegen_jump(fs); + + p_f = code_label(fs, reg, 0, 1); + p_t = code_label(fs, reg, 1, 0); + codegen_patchtohere(fs, fj); + } + final = codegen_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.info = reg; + e->k = VNONRELOC; +} + +void codegen_exp2nextreg(ktap_funcstate *fs, ktap_expdesc *e) +{ + codegen_dischargevars(fs, e); + freeexp(fs, e); + codegen_reserveregs(fs, 1); + exp2reg(fs, e, fs->freereg - 1); +} + +int codegen_exp2anyreg(ktap_funcstate *fs, ktap_expdesc *e) +{ + codegen_dischargevars(fs, e); + if (e->k == VNONRELOC) { + if (!hasjumps(e)) + return e->u.info; /* exp is already in a register */ + if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.info); /* put value on it */ + return e->u.info; + } + } + codegen_exp2nextreg(fs, e); /* default */ + return e->u.info; +} + +void codegen_exp2anyregup(ktap_funcstate *fs, ktap_expdesc *e) +{ + if (e->k != VUPVAL || hasjumps(e)) + codegen_exp2anyreg(fs, e); +} + +void codegen_exp2val(ktap_funcstate *fs, ktap_expdesc *e) +{ + if (hasjumps(e)) + codegen_exp2anyreg(fs, e); + else + codegen_dischargevars(fs, e); +} + +int codegen_exp2RK(ktap_funcstate *fs, ktap_expdesc *e) +{ + codegen_exp2val(fs, e); + switch (e->k) { + case VTRUE: + case VFALSE: + case VNIL: { + if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ + e->u.info = (e->k == VNIL) ? nilK(fs) : + boolK(fs, (e->k == VTRUE)); + e->k = VK; + return RKASK(e->u.info); + } + else + break; + } + case VKNUM: { + e->u.info = codegen_numberK(fs, e->u.nval); + e->k = VK; + /* go through */ + } + case VK: { + if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */ + return RKASK(e->u.info); + else + break; + } + default: + break; + } + /* not a constant in the right range: put it in a register */ + return codegen_exp2anyreg(fs, e); +} + +void codegen_storevar(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex) +{ + switch (var->k) { + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.info); + return; + } + case VUPVAL: { + int e = codegen_exp2anyreg(fs, ex); + codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); + break; + } + case VINDEXED: { + OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; + int e = codegen_exp2RK(fs, ex); + codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); + break; + } + default: + ktap_assert(0); /* invalid var kind to store */ + break; + } + + freeexp(fs, ex); +} + +void codegen_storeincr(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex) +{ + switch (var->k) { +#if 0 /*current not supported */ + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.info); + return; + } + case VUPVAL: { + int e = codegen_exp2anyreg(fs, ex); + codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); + break; + } +#endif + case VINDEXED: { + OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE_INCR : + OP_SETTABUP_INCR; + int e = codegen_exp2RK(fs, ex); + codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); + break; + } + default: + ktap_assert(0); /* invalid var kind to store */ + break; + } + + freeexp(fs, ex); +} + + +void codegen_self(ktap_funcstate *fs, ktap_expdesc *e, ktap_expdesc *key) +{ + int ereg; + + codegen_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' was placed */ + freeexp(fs, e); + e->u.info = fs->freereg; /* base register for op_self */ + e->k = VNONRELOC; + codegen_reserveregs(fs, 2); /* function and 'self' produced by op_self */ + codegen_codeABC(fs, OP_SELF, e->u.info, ereg, codegen_exp2RK(fs, key)); + freeexp(fs, key); +} + +static void invertjump(ktap_funcstate *fs, ktap_expdesc *e) +{ + ktap_instruction *pc = getjumpcontrol(fs, e->u.info); + ktap_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); + SETARG_A(*pc, !(GETARG_A(*pc))); +} + +static int jumponcond(ktap_funcstate *fs, ktap_expdesc *e, int cond) +{ + if (e->k == VRELOCABLE) { + ktap_instruction ie = getcode(fs, e); + if (GET_OPCODE(ie) == OP_NOT) { + fs->pc--; /* remove previous OP_NOT */ + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); +} + +void codegen_goiftrue(ktap_funcstate *fs, ktap_expdesc *e) +{ + int pc; /* pc of last jump */ + + codegen_dischargevars(fs, e); + switch (e->k) { + case VJMP: { + invertjump(fs, e); + pc = e->u.info; + break; + } + case VK: case VKNUM: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + default: + pc = jumponcond(fs, e, 0); + break; + } + + codegen_concat(fs, &e->f, pc); /* insert last jump in `f' list */ + codegen_patchtohere(fs, e->t); + e->t = NO_JUMP; +} + +void codegen_goiffalse(ktap_funcstate *fs, ktap_expdesc *e) +{ + int pc; /* pc of last jump */ + codegen_dischargevars(fs, e); + + switch (e->k) { + case VJMP: { + pc = e->u.info; + break; + } + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + default: + pc = jumponcond(fs, e, 1); + break; + } + codegen_concat(fs, &e->t, pc); /* insert last jump in `t' list */ + codegen_patchtohere(fs, e->f); + e->f = NO_JUMP; +} + +static void codenot(ktap_funcstate *fs, ktap_expdesc *e) +{ + codegen_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; + break; + } + case VK: case VKNUM: case VTRUE: { + e->k = VFALSE; + break; + } + case VJMP: { + invertjump(fs, e); + break; + } + case VRELOCABLE: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.info = codegen_codeABC(fs, OP_NOT, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + default: + ktap_assert(0); /* cannot happen */ + break; + } + + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); + removevalues(fs, e->t); +} + +void codegen_indexed(ktap_funcstate *fs, ktap_expdesc *t, ktap_expdesc *k) +{ + ktap_assert(!hasjumps(t)); + t->u.ind.t = t->u.info; + t->u.ind.idx = codegen_exp2RK(fs, k); + t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL + : check_exp(vkisinreg(t->k), VLOCAL); + t->k = VINDEXED; +} + +static int constfolding(OpCode op, ktap_expdesc *e1, ktap_expdesc *e2) +{ + ktap_number r; + + if (!isnumeral(e1) || !isnumeral(e2)) + return 0; + + if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0) + return 0; /* do not attempt to divide by 0 */ + + if (op == OP_POW) + return 0; /* ktap current do not suppor pow arith */ + + r = ktapc_arith(op - OP_ADD + KTAP_OPADD, e1->u.nval, e2->u.nval); + e1->u.nval = r; + return 1; +} + +static void codearith(ktap_funcstate *fs, OpCode op, + ktap_expdesc *e1, ktap_expdesc *e2, int line) +{ + if (constfolding(op, e1, e2)) + return; + else { + int o2 = (op != OP_UNM && op != OP_LEN) ? codegen_exp2RK(fs, e2) : 0; + int o1 = codegen_exp2RK(fs, e1); + + if (o1 > o2) { + freeexp(fs, e1); + freeexp(fs, e2); + } else { + freeexp(fs, e2); + freeexp(fs, e1); + } + e1->u.info = codegen_codeABC(fs, op, 0, o1, o2); + e1->k = VRELOCABLE; + codegen_fixline(fs, line); + } +} + +static void codecomp(ktap_funcstate *fs, OpCode op, int cond, ktap_expdesc *e1, + ktap_expdesc *e2) +{ + int o1 = codegen_exp2RK(fs, e1); + int o2 = codegen_exp2RK(fs, e2); + + freeexp(fs, e2); + freeexp(fs, e1); + if (cond == 0 && op != OP_EQ) { + int temp; /* exchange args to replace by `<' or `<=' */ + temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ + cond = 1; + } + e1->u.info = condjump(fs, op, cond, o1, o2); + e1->k = VJMP; +} + +void codegen_prefix(ktap_funcstate *fs, UnOpr op, ktap_expdesc *e, int line) +{ + ktap_expdesc e2; + + e2.t = e2.f = NO_JUMP; + e2.k = VKNUM; + e2.u.nval = 0; + + switch (op) { + case OPR_MINUS: { + if (isnumeral(e)) /* minus constant? */ + e->u.nval = ktap_numunm(e->u.nval); /* fold it */ + else { + codegen_exp2anyreg(fs, e); + codearith(fs, OP_UNM, e, &e2, line); + } + break; + } + case OPR_NOT: + codenot(fs, e); + break; + case OPR_LEN: { + codegen_exp2anyreg(fs, e); /* cannot operate on constants */ + codearith(fs, OP_LEN, e, &e2, line); + break; + } + default: + ktap_assert(0); + } +} + +void codegen_infix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *v) +{ + switch (op) { + case OPR_AND: { + codegen_goiftrue(fs, v); + break; + } + case OPR_OR: { + codegen_goiffalse(fs, v); + break; + } + case OPR_CONCAT: { + codegen_exp2nextreg(fs, v); /* operand must be on the `stack' */ + break; + } + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { + if (!isnumeral(v)) codegen_exp2RK(fs, v); + break; + } + default: + codegen_exp2RK(fs, v); + break; + } +} + +void codegen_posfix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *e1, ktap_expdesc *e2, int line) +{ + switch (op) { + case OPR_AND: { + ktap_assert(e1->t == NO_JUMP); /* list must be closed */ + codegen_dischargevars(fs, e2); + codegen_concat(fs, &e2->f, e1->f); + *e1 = *e2; + break; + } + case OPR_OR: { + ktap_assert(e1->f == NO_JUMP); /* list must be closed */ + codegen_dischargevars(fs, e2); + codegen_concat(fs, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: { + codegen_exp2val(fs, e2); + if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { + ktap_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); + freeexp(fs, e1); + SETARG_B(getcode(fs, e2), e1->u.info); + e1->k = VRELOCABLE; e1->u.info = e2->u.info; + } else { + codegen_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codearith(fs, OP_CONCAT, e1, e2, line); + } + break; + } + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { + codearith(fs, (OpCode)(op - OPR_ADD + OP_ADD), e1, e2, line); + break; + } + case OPR_EQ: case OPR_LT: case OPR_LE: { + codecomp(fs, (OpCode)(op - OPR_EQ + OP_EQ), 1, e1, e2); + break; + } + case OPR_NE: case OPR_GT: case OPR_GE: { + codecomp(fs, (OpCode)(op - OPR_NE + OP_EQ), 0, e1, e2); + break; + } + default: + ktap_assert(0); + } +} + +void codegen_fixline(ktap_funcstate *fs, int line) +{ + fs->f->lineinfo[fs->pc - 1] = line; +} + +void codegen_setlist(ktap_funcstate *fs, int base, int nelems, int tostore) +{ + int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + int b = (tostore == KTAP_MULTRET) ? 0 : tostore; + + ktap_assert(tostore != 0); + if (c <= MAXARG_C) + codegen_codeABC(fs, OP_SETLIST, base, b, c); + else if (c <= MAXARG_Ax) { + codegen_codeABC(fs, OP_SETLIST, base, b, 0); + codeextraarg(fs, c); + } else + lex_syntaxerror(fs->ls, "constructor too long"); + fs->freereg = base + 1; /* free registers with list values */ +} + diff --git a/drivers/staging/ktap/userspace/dump.c b/drivers/staging/ktap/userspace/dump.c new file mode 100644 index 000000000000..088b08d0fa8e --- /dev/null +++ b/drivers/staging/ktap/userspace/dump.c @@ -0,0 +1,187 @@ +/* + * dump.c - save precompiled ktap chunks + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../include/ktap_types.h" +#include "../include/ktap_opcodes.h" +#include "ktapc.h" + + +typedef struct { + ktap_writer writer; + void *data; + int strip; + int status; +} DumpState; + +#define DumpMem(b, n, size, D) DumpBlock(b, (n)*(size), D) +#define DumpVar(x, D) DumpMem(&x, 1, sizeof(x), D) + +static void DumpBlock(const void *b, size_t size, DumpState *D) +{ + if (D->status == 0) + D->status = ((D->writer))(b, size, D->data); +} + +static void DumpChar(int y, DumpState *D) +{ + char x = (char)y; + DumpVar(x, D); +} + +static void DumpInt(int x, DumpState *D) +{ + DumpVar(x, D); +} + +static void DumpNumber(ktap_number x, DumpState *D) +{ + DumpVar(x,D); +} + +static void DumpVector(const void *b, int n, size_t size, DumpState *D) +{ + DumpInt(n, D); + DumpMem(b, n, size, D); +} + +static void DumpString(const ktap_string *s, DumpState *D) +{ + if (s == NULL) { + int size = 0; + DumpVar(size, D); + } else { + int size = s->tsv.len + 1; /* include trailing '\0' */ + DumpVar(size, D); + DumpBlock(getstr(s), size * sizeof(char), D); + } +} + +#define DumpCode(f, D) DumpVector(f->code, f->sizecode, sizeof(ktap_instruction), D) + +static void DumpFunction(const ktap_proto *f, DumpState *D); + +static void DumpConstants(const ktap_proto *f, DumpState *D) +{ + int i, n = f->sizek; + + DumpInt(n, D); + for (i = 0; i < n; i++) { + const ktap_value* o=&f->k[i]; + DumpChar(ttypenv(o), D); + switch (ttypenv(o)) { + case KTAP_TNIL: + break; + case KTAP_TBOOLEAN: + DumpChar(bvalue(o), D); + break; + case KTAP_TNUMBER: + DumpNumber(nvalue(o), D); + break; + case KTAP_TSTRING: + DumpString(rawtsvalue(o), D); + break; + default: + printf("ktap: DumpConstants with unknown vaule type %d\n", ttypenv(o)); + ktap_assert(0); + } + } + n = f->sizep; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpFunction(f->p[i], D); +} + +static void DumpUpvalues(const ktap_proto *f, DumpState *D) +{ + int i, n = f->sizeupvalues; + + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpChar(f->upvalues[i].instack, D); + DumpChar(f->upvalues[i].idx, D); + } +} + +static void DumpDebug(const ktap_proto *f, DumpState *D) +{ + int i,n; + + DumpString((D->strip) ? NULL : f->source, D); + n= (D->strip) ? 0 : f->sizelineinfo; + DumpVector(f->lineinfo, n, sizeof(int), D); + n = (D->strip) ? 0 : f->sizelocvars; + DumpInt(n, D); + + for (i = 0; i < n; i++) { + DumpString(f->locvars[i].varname, D); + DumpInt(f->locvars[i].startpc, D); + DumpInt(f->locvars[i].endpc, D); + } + n = (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpString(f->upvalues[i].name, D); +} + +static void DumpFunction(const ktap_proto *f, DumpState *D) +{ + DumpInt(f->linedefined, D); + DumpInt(f->lastlinedefined, D); + DumpChar(f->numparams, D); + DumpChar(f->is_vararg, D); + DumpChar(f->maxstacksize, D); + DumpCode(f, D); + DumpConstants(f, D); + DumpUpvalues(f, D); + DumpDebug(f, D); +} + +static void DumpHeader(DumpState *D) +{ + u8 h[KTAPC_HEADERSIZE]; + + kp_header(h); + DumpBlock(h, KTAPC_HEADERSIZE, D); +} + +/* + * dump ktap function as precompiled chunk + */ +int ktapc_dump(const ktap_proto *f, ktap_writer w, void *data, int strip) +{ + DumpState D; + + D.writer = w; + D.data = data; + D.strip = strip; + D.status = 0; + DumpHeader(&D); + DumpFunction(f, &D); + return D.status; +} diff --git a/drivers/staging/ktap/userspace/eventdef.c b/drivers/staging/ktap/userspace/eventdef.c new file mode 100644 index 000000000000..76a68ac8aabc --- /dev/null +++ b/drivers/staging/ktap/userspace/eventdef.c @@ -0,0 +1,588 @@ +/* + * eventdef.c - ktap eventdef parser + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <fcntl.h> + +#include "../include/ktap_types.h" +#include "../include/ktap_opcodes.h" +#include "ktapc.h" + +static char tracing_events_path[] = "/sys/kernel/debug/tracing/events"; + +#define IDS_ARRAY_SIZE 4096 +static u8 *ids_array; + +#define set_id(id) \ + do { \ + ids_array[id/8] = ids_array[id/8] | (1 << (id%8)); \ + } while(0) + +#define clear_id(id) \ + do { \ + ids_array[id/8] = ids_array[id/8] & ~ (1 << (id%8)); \ + } while(0) + + +static int get_digit_len(int id) +{ + int len = -1; + + if (id < 10) + len = 1; + else if (id < 100) + len = 2; + else if (id < 1000) + len = 3; + else if (id < 10000) + len = 4; + else if (id < 100000) + len = 5; + + return len; +} + +static char *get_idstr(char *filter) +{ + char *idstr, *ptr; + int total_len = 0; + int filter_len; + int i; + + filter_len = filter ? strlen(filter) : 0; + + for (i = 0; i < IDS_ARRAY_SIZE*8; i++) { + if (ids_array[i/8] & (1 << (i%8))) + total_len += get_digit_len(i) + 1; + } + + if (!total_len) + return NULL; + + idstr = malloc(total_len + filter_len + 1); + if (!idstr) + return NULL; + + memset(idstr, 0, total_len + filter_len + 1); + ptr = idstr; + for (i = 0; i < IDS_ARRAY_SIZE*8; i++) { + if (ids_array[i/8] & (1 << (i%8))) { + char digits[32] = {0}; + int len; + + sprintf(digits, "%d ", i); + len = strlen(digits); + strncpy(ptr, digits, len); + ptr += len; + } + } + + if (filter) + memcpy(ptr, filter, strlen(filter)); + + return idstr; +} + +static int add_event(char *evtid_path) +{ + char id_buf[24]; + int id, fd; + + fd = open(evtid_path, O_RDONLY); + if (fd < 0) { + /* + * some tracepoint doesn't have id file, like ftrace, + * return success in here, and don't print error. + */ + verbose_printf("warning: cannot open file %s\n", evtid_path); + return 0; + } + + if (read(fd, id_buf, sizeof(id_buf)) < 0) { + fprintf(stderr, "read file error %s\n", evtid_path); + close(fd); + return -1; + } + + id = atoll(id_buf); + + if (id >= IDS_ARRAY_SIZE * 8) { + fprintf(stderr, "tracepoint id(%d) is bigger than %d\n", id, + IDS_ARRAY_SIZE * 8); + close(fd); + return -1; + } + + set_id(id); + + close(fd); + return 0; +} + +static int add_tracepoint(char *sys_name, char *evt_name) +{ + char evtid_path[PATH_MAX] = {0}; + + + snprintf(evtid_path, PATH_MAX, "%s/%s/%s/id", tracing_events_path, + sys_name, evt_name); + return add_event(evtid_path); +} + +static int add_tracepoint_multi_event(char *sys_name, char *evt_name) +{ + char evt_path[PATH_MAX]; + struct dirent *evt_ent; + DIR *evt_dir; + int ret = 0; + + snprintf(evt_path, PATH_MAX, "%s/%s", tracing_events_path, sys_name); + evt_dir = opendir(evt_path); + if (!evt_dir) { + perror("Can't open event dir"); + return -1; + } + + while (!ret && (evt_ent = readdir(evt_dir))) { + if (!strcmp(evt_ent->d_name, ".") + || !strcmp(evt_ent->d_name, "..") + || !strcmp(evt_ent->d_name, "enable") + || !strcmp(evt_ent->d_name, "filter")) + continue; + + if (!strglobmatch(evt_ent->d_name, evt_name)) + continue; + + ret = add_tracepoint(sys_name, evt_ent->d_name); + } + + closedir(evt_dir); + return ret; +} + +static int add_tracepoint_event(char *sys_name, char *evt_name) +{ + return strpbrk(evt_name, "*?") ? + add_tracepoint_multi_event(sys_name, evt_name) : + add_tracepoint(sys_name, evt_name); +} + +static int add_tracepoint_multi_sys(char *sys_name, char *evt_name) +{ + struct dirent *events_ent; + DIR *events_dir; + int ret = 0; + + events_dir = opendir(tracing_events_path); + if (!events_dir) { + perror("Can't open event dir"); + return -1; + } + + while (!ret && (events_ent = readdir(events_dir))) { + if (!strcmp(events_ent->d_name, ".") + || !strcmp(events_ent->d_name, "..") + || !strcmp(events_ent->d_name, "enable") + || !strcmp(events_ent->d_name, "header_event") + || !strcmp(events_ent->d_name, "header_page")) + continue; + + if (!strglobmatch(events_ent->d_name, sys_name)) + continue; + + ret = add_tracepoint_event(events_ent->d_name, + evt_name); + } + + closedir(events_dir); + return ret; +} + +static int parse_events_add_tracepoint(char *sys, char *event) +{ + if (strpbrk(sys, "*?")) + return add_tracepoint_multi_sys(sys, event); + else + return add_tracepoint_event(sys, event); +} + +enum { + KPROBE_EVENT, + UPROBE_EVENT, +}; + +struct probe_list { + struct probe_list *next; + int type; + int kp_seq; + char *probe_event; +}; + +static struct probe_list *probe_list_head; + +#define KPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/kprobe_events" + +static int parse_events_add_kprobe(char *old_event) +{ + static int event_seq = 0; + struct probe_list *pl; + char probe_event[128] = {0}; + char event_id_path[128] = {0}; + char *event; + char *r; + int fd; + int ret; + + fd = open(KPROBE_EVENTS_PATH, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "Cannot open %s\n", KPROBE_EVENTS_PATH); + return -1; + } + + event = strdup(old_event); + r = strstr(event, "%return"); + if (r) { + memset(r, ' ', 7); + snprintf(probe_event, 128, "r:kprobes/kp%d %s", + event_seq, event); + } else + snprintf(probe_event, 128, "p:kprobes/kp%d %s", + event_seq, event); + + free(event); + + verbose_printf("kprobe event %s\n", probe_event); + ret = write(fd, probe_event, strlen(probe_event)); + if (ret <= 0) { + fprintf(stderr, "Cannot write %s to %s\n", probe_event, + KPROBE_EVENTS_PATH); + close(fd); + return -1; + } + + close(fd); + + pl = malloc(sizeof(struct probe_list)); + if (!pl) + return -1; + + pl->type = KPROBE_EVENT; + pl->kp_seq = event_seq; + pl->next = probe_list_head; + probe_list_head = pl; + + sprintf(event_id_path, "/sys/kernel/debug/tracing/events/kprobes/kp%d/id", + event_seq); + ret = add_event(event_id_path); + if (ret < 0) + return -1; + + event_seq++; + return 0; +} + +#define UPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/uprobe_events" + +static int parse_events_add_uprobe(char *old_event) +{ + static int event_seq = 0; + struct probe_list *pl; + char probe_event[128] = {0}; + char event_id_path[128] = {0}; + char *event; + char *r; + int fd; + int ret; + + fd = open(UPROBE_EVENTS_PATH, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "Cannot open %s\n", UPROBE_EVENTS_PATH); + return -1; + } + + event = strdup(old_event); + r = strstr(event, "%return"); + if (r) { + memset(r, ' ', 7); + snprintf(probe_event, 128, "r:uprobes/kp%d %s", + event_seq, event); + } else + snprintf(probe_event, 128, "p:uprobes/kp%d %s", + event_seq, event); + + free(event); + + verbose_printf("uprobe event %s\n", probe_event); + ret = write(fd, probe_event, strlen(probe_event)); + if (ret <= 0) { + fprintf(stderr, "Cannot write %s to %s\n", probe_event, + UPROBE_EVENTS_PATH); + close(fd); + return -1; + } + + close(fd); + + pl = malloc(sizeof(struct probe_list)); + if (!pl) + return -1; + + pl->type = UPROBE_EVENT; + pl->kp_seq = event_seq; + pl->next = probe_list_head; + probe_list_head = pl; + + sprintf(event_id_path, "/sys/kernel/debug/tracing/events/uprobes/kp%d/id", + event_seq); + ret = add_event(event_id_path); + if (ret < 0) + return -1; + + event_seq++; + return 0; +} + +static int parse_events_add_probe(char *old_event) +{ + char *separator; + + separator = strchr(old_event, ':'); + if (!separator || (separator == old_event)) + return parse_events_add_kprobe(old_event); + else + return parse_events_add_uprobe(old_event); +} + +static int parse_events_add_stapsdt(char *old_event) +{ + printf("Currently ktap don't support stapsdt, please waiting\n"); + + return -1; +} + +static void strim(char *s) +{ + size_t size; + char *end; + + size = strlen(s); + if (!size) + return; + + end = s + size -1; + while (end >= s && isspace(*end)) + end--; + + *(end + 1) = '\0'; +} + +static int get_sys_event_filter_str(char *start, + char **sys, char **event, char **filter) +{ + char *separator, *separator2, *ptr, *end; + + while (*start == ' ') + start++; + + /* find sys */ + separator = strchr(start, ':'); + if (!separator || (separator == start)) { + return -1; + } + + ptr = malloc(separator - start + 1); + if (!ptr) + return -1; + + strncpy(ptr, start, separator - start); + ptr[separator - start] = '\0'; + + strim(ptr); + *sys = ptr; + + if (!strcmp(*sys, "probe") && (*(separator + 1) == '/')) { + /* it's uprobe event */ + separator2 = strchr(separator + 1, ':'); + if (!separator2) + return -1; + } else + separator2 = separator; + + /* find filter */ + end = start + strlen(start); + while (*--end == ' ') { + } + + if (*end == '/') { + char *filter_start; + + filter_start = strchr(separator2, '/'); + if (filter_start == end) + return -1; + + ptr = malloc(end - filter_start + 2); + if (!ptr) + return -1; + + memcpy(ptr, filter_start, end - filter_start + 1); + ptr[end - filter_start + 1] = '\0'; + + *filter = ptr; + + end = filter_start; + } else { + *filter = NULL; + end++; + } + + /* find event */ + ptr = malloc(end - separator); + if (!ptr) + return -1; + + memcpy(ptr, separator + 1, end - separator - 1); + ptr[end - separator - 1] = '\0'; + + strim(ptr); + *event = ptr; + + return 0; +} + +static char *get_next_eventdef(char *str) +{ + char *separator; + + separator = strchr(str, ','); + if (!separator) + return str + strlen(str); + + *separator = '\0'; + return separator + 1; +} + +ktap_string *ktapc_parse_eventdef(ktap_string *eventdef) +{ + const char *def_str = getstr(eventdef); + char *str = strdup(def_str); + char *sys, *event, *filter, *idstr, *g_idstr, *next; + ktap_string *ts; + int ret; + + if (!ids_array) { + ids_array = malloc(IDS_ARRAY_SIZE); + if (!ids_array) + return NULL; + } + + g_idstr = malloc(4096); + if (!g_idstr) + return NULL; + + memset(g_idstr, 0, 4096); + + parse_next_eventdef: + memset(ids_array, 0, IDS_ARRAY_SIZE); + + next = get_next_eventdef(str); + + if (get_sys_event_filter_str(str, &sys, &event, &filter)) + goto error; + + verbose_printf("parse_eventdef: sys[%s], event[%s], filter[%s]\n", + sys, event, filter); + + if (!strcmp(sys, "probe")) + ret = parse_events_add_probe(event); + else if (!strcmp(sys, "stapsdt")) + ret = parse_events_add_stapsdt(event); + else + ret = parse_events_add_tracepoint(sys, event); + + if (ret) + goto error; + + /* don't trace ftrace:function when all tracepoints enabled */ + if (!strcmp(sys, "*")) + clear_id(1); + + idstr = get_idstr(filter); + if (!idstr) + goto error; + + str = next; + + g_idstr = strcat(g_idstr, idstr); + g_idstr = strcat(g_idstr, ","); + + if (*next != '\0') + goto parse_next_eventdef; + + ts = ktapc_ts_new(g_idstr); + free(g_idstr); + + return ts; + error: + cleanup_event_resources(); + return NULL; +} + +void cleanup_event_resources(void) +{ + struct probe_list *pl; + const char *path; + char probe_event[32] = {0}; + int fd, ret; + + for (pl = probe_list_head; pl; pl = pl->next) { + if (pl->type == KPROBE_EVENT) { + path = KPROBE_EVENTS_PATH; + snprintf(probe_event, 32, "-:kprobes/kp%d", pl->kp_seq); + } else if (pl->type == UPROBE_EVENT) { + path = UPROBE_EVENTS_PATH; + snprintf(probe_event, 32, "-:uprobes/kp%d", pl->kp_seq); + } else { + fprintf(stderr, "Cannot cleanup event type %d\n", pl->type); + continue; + } + + fd = open(path, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "Cannot open %s\n", UPROBE_EVENTS_PATH); + continue; + } + + ret = write(fd, probe_event, strlen(probe_event)); + if (ret <= 0) { + fprintf(stderr, "Cannot write %s to %s\n", probe_event, + path); + close(fd); + continue; + } + + close(fd); + } +} + diff --git a/drivers/staging/ktap/userspace/ktapc.h b/drivers/staging/ktap/userspace/ktapc.h new file mode 100644 index 000000000000..879cd29d8c94 --- /dev/null +++ b/drivers/staging/ktap/userspace/ktapc.h @@ -0,0 +1,376 @@ +/* + * ktapc.h + * only can be included by userspace compiler + */ + +#include <ctype.h> + +typedef int bool; +#define false 0 +#define true 1 + +#define MAX_INT ((int)(~0U>>1)) +#define UCHAR_MAX 255 + +#define MAX_SIZET ((size_t)(~(size_t)0)-2) + +#define KTAP_ERRSYNTAX 3 + +/* + * KTAP_IDSIZE gives the maximum size for the description of the source + * of a function in debug information. + * CHANGE it if you want a different size. + */ +#define KTAP_IDSIZE 60 + + +#define FIRST_RESERVED 257 + +/* + * maximum depth for nested C calls and syntactical nested non-terminals + * in a program. (Value must fit in an unsigned short int.) + */ +#define KTAP_MAXCCALLS 200 + +#define KTAP_MULTRET (-1) + + +#define SHRT_MAX UCHAR_MAX + +#define MAXUPVAL UCHAR_MAX + + +/* maximum stack for a ktap function */ +#define MAXSTACK 250 + +#define islalpha(c) (isalpha(c) || (c) == '_') +#define islalnum(c) (isalnum(c) || (c) == '_') + +#define isreserved(s) ((s)->tsv.tt == KTAP_TSHRSTR && (s)->tsv.extra > 0) + +#define ktap_numeq(a,b) ((a)==(b)) +#define ktap_numisnan(L,a) (!ktap_numeq((a), (a))) + +#define ktap_numunm(a) (-(a)) + +/* + * ** Comparison and arithmetic functions + * */ + +#define KTAP_OPADD 0 /* ORDER TM */ +#define KTAP_OPSUB 1 +#define KTAP_OPMUL 2 +#define KTAP_OPDIV 3 +#define KTAP_OPMOD 4 +#define KTAP_OPPOW 5 +#define KTAP_OPUNM 6 + +#define KTAP_OPEQ 0 +#define KTAP_OPLT 1 +#define KTAP_OPLE 2 + + +/* + * WARNING: if you change the order of this enumeration, + * grep "ORDER RESERVED" + */ +enum RESERVED { + /* terminal symbols denoted by reserved words */ + TK_TRACE = FIRST_RESERVED, TK_TRACE_END, + TK_ARGEVENT, TK_ARGNAME, + TK_ARG1, TK_ARG2, TK_ARG3, TK_ARG4, TK_ARG5, TK_ARG6, TK_ARG7, TK_ARG8, + TK_ARG9, TK_PROFILE, TK_TICK, + TK_AND, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + /* other terminal symbols */ + TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_INCR, TK_DBCOLON, + TK_EOS, TK_NUMBER, TK_NAME, TK_STRING +}; + +/* number of reserved words */ +#define NUM_RESERVED ((int)(TK_WHILE-FIRST_RESERVED + 1)) + +#define EOZ (0) /* end of stream */ + +typedef union { + ktap_number r; + ktap_string *ts; +} ktap_seminfo; /* semantics information */ + + +typedef struct ktap_token { + int token; + ktap_seminfo seminfo; +} ktap_token; + +typedef struct ktap_mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} ktap_mbuffer; + +#define mbuff_init(buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) +#define mbuff(buff) ((buff)->buffer) +#define mbuff_reset(buff) ((buff)->n = 0, memset((buff)->buffer, 0, (buff)->buffsize)) +#define mbuff_len(buff) ((buff)->n) +#define mbuff_size(buff) ((buff)->buffsize) + +#define mbuff_resize(buff, size) \ + (ktapc_realloc((buff)->buffer, (buff)->buffsize, size, char), \ + (buff)->buffsize = size) + +#define mbuff_free(buff) mbuff_resize(buff, 0) + + +/* + * state of the lexer plus state of the parser when shared by all + * functions + */ +typedef struct ktap_lexstate { + char *ptr; /* source file reading position */ + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token `consumed' */ + ktap_token t; /* current token */ + ktap_token lookahead; /* look ahead token */ + struct ktap_funcstate *fs; /* current function (parser) */ + ktap_mbuffer *buff; /* buffer for tokens */ + struct ktap_dyndata *dyd; /* dynamic structures used by the parser */ + ktap_string *source; /* current source name */ + ktap_string *envn; /* environment variable name */ + char decpoint; /* locale decimal point */ + int nCcalls; +} ktap_lexstate; + + +/* + * Expression descriptor + */ +typedef enum { + VVOID, /* no value */ + VNIL, + VTRUE, + VFALSE, + VK, /* info = index of constant in `k' */ + VKNUM, /* nval = numerical value */ + VNONRELOC, /* info = result register */ + VLOCAL, /* info = local register */ + VUPVAL, /* info = index of upvalue in 'upvalues' */ + VINDEXED, /* t = table register/upvalue; idx = index R/K */ + VJMP, /* info = instruction pc */ + VRELOCABLE, /* info = instruction pc */ + VCALL, /* info = instruction pc */ + VVARARG, /* info = instruction pc */ + VEVENT, + VEVENTNAME, + VEVENTARG, +} expkind; + + +#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) +#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) + +typedef struct ktap_expdesc { + expkind k; + union { + struct { /* for indexed variables (VINDEXED) */ + short idx; /* index (R/K) */ + u8 t; /* table (register or upvalue) */ + u8 vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ + } ind; + int info; /* for generic use */ + ktap_number nval; /* for VKNUM */ + } u; + int t; /* patch list of `exit when true' */ + int f; /* patch list of `exit when false' */ +} ktap_expdesc; + + +typedef struct ktap_vardesc { + short idx; /* variable index in stack */ +} ktap_vardesc; + + +/* description of pending goto statements and label statements */ +typedef struct ktap_labeldesc { + ktap_string *name; /* label identifier */ + int pc; /* position in code */ + int line; /* line where it appeared */ + u8 nactvar; /* local level where it appears in current block */ +} ktap_labeldesc; + + +/* list of labels or gotos */ +typedef struct ktap_labellist { + ktap_labeldesc *arr; /* array */ + int n; /* number of entries in use */ + int size; /* array size */ +} ktap_labellist; + + +/* dynamic structures used by the parser */ +typedef struct ktap_dyndata { + struct { /* list of active local variables */ + ktap_vardesc *arr; + int n; + int size; + } actvar; + ktap_labellist gt; /* list of pending gotos */ + ktap_labellist label; /* list of active labels */ +} ktap_dyndata; + + +/* control of blocks */ +struct ktap_blockcnt; /* defined in lparser.c */ + + +/* state needed to generate code for a given function */ +typedef struct ktap_funcstate { + ktap_proto *f; /* current function header */ + ktap_table *h; /* table to find (and reuse) elements in `k' */ + struct ktap_funcstate *prev; /* enclosing function */ + struct ktap_lexstate *ls; /* lexical state */ + struct ktap_blockcnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to `ncode') */ + int lasttarget; /* 'label' of last 'jump label' */ + int jpc; /* list of pending jumps to `pc' */ + int nk; /* number of elements in `k' */ + int np; /* number of elements in `p' */ + int firstlocal; /* index of first local var (in ktap_dyndata array) */ + short nlocvars; /* number of elements in 'f->locvars' */ + u8 nactvar; /* number of active local variables */ + u8 nups; /* number of upvalues */ + u8 freereg; /* first free register */ +} ktap_funcstate; + + +/* + * Marks the end of a patch list. It is an invalid value both as an absolute + * address, and as a list link (would link an element to itself). + */ +#define NO_JUMP (-1) + + +/* + * grep "ORDER OPR" if you change these enums (ORDER OP) + */ +typedef enum BinOpr { + OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, + OPR_CONCAT, + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + + +typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; + + +#define getcode(fs,e) ((fs)->f->code[(e)->u.info]) + +#define codegen_codeAsBx(fs,o,A,sBx) codegen_codeABx(fs,o,A,(sBx)+MAXARG_sBx) + +#define codegen_setmultret(fs,e) codegen_setreturns(fs, e, KTAP_MULTRET) + +#define codegen_jumpto(fs,t) codegen_patchlist(fs, codegen_jump(fs), t) + + +#define ktapc_realloc(v, osize, nsize, t) \ + ((v) = (t *)ktapc_reallocv(v, osize * sizeof(t), nsize * sizeof(t))) + +#define ktapc_reallocvector(v,oldn,n,t) ktapc_realloc(v,oldn,n,t) + + +#define ktapc_growvector(v,nelems,size,t,limit,e) \ + if ((nelems)+1 > (size)) \ + ((v)=(t *)ktapc_growaux(v,&(size),sizeof(t),limit,e)) + + +void lex_init(); +ktap_string *lex_newstring(ktap_lexstate *ls, const char *str, size_t l); +const char *lex_token2str(ktap_lexstate *ls, int token); +void lex_syntaxerror(ktap_lexstate *ls, const char *msg); +void lex_setinput(ktap_lexstate *ls, char *ptr, ktap_string *source, int firstchar); +void lex_next(ktap_lexstate *ls); +int lex_lookahead(ktap_lexstate *ls); +void lex_read_string_until(ktap_lexstate *ls, int c); +ktap_closure *ktapc_parser(char *pos, const char *name); +ktap_string *ktapc_ts_new(const char *str); +int ktapc_ts_eqstr(ktap_string *a, ktap_string *b); +ktap_string *ktapc_ts_newlstr(const char *str, size_t l); +ktap_proto *ktapc_newproto(); +ktap_table *ktapc_table_new(); +const ktap_value *ktapc_table_get(ktap_table *t, const ktap_value *key); +void ktapc_table_setvalue(ktap_table *t, const ktap_value *key, ktap_value *val); +ktap_closure *ktapc_newlclosure(int n); +char *ktapc_sprintf(const char *fmt, ...); + +void *ktapc_reallocv(void *block, size_t osize, size_t nsize); +void *ktapc_growaux(void *block, int *size, size_t size_elems, int limit, + const char *what); + +void ktapio_exit(void); +int ktapio_create(const char *output_filename); + +ktap_string *ktapc_parse_eventdef(ktap_string *eventdef); +void cleanup_event_resources(void); + +extern int verbose; +#define verbose_printf(...) \ + if (verbose) \ + printf("[verbose] " __VA_ARGS__); + +#define ktapc_equalobj(t1, t2) kp_equalobjv(NULL, t1, t2) + + +#include "../include/ktap_opcodes.h" + +int codegen_stringK(ktap_funcstate *fs, ktap_string *s); +void codegen_indexed(ktap_funcstate *fs, ktap_expdesc *t, ktap_expdesc *k); +void codegen_setreturns(ktap_funcstate *fs, ktap_expdesc *e, int nresults); +void codegen_reserveregs(ktap_funcstate *fs, int n); +void codegen_exp2nextreg(ktap_funcstate *fs, ktap_expdesc *e); +void codegen_nil(ktap_funcstate *fs, int from, int n); +void codegen_patchlist(ktap_funcstate *fs, int list, int target); +void codegen_patchclose(ktap_funcstate *fs, int list, int level); +int codegen_jump(ktap_funcstate *fs); +void codegen_patchtohere(ktap_funcstate *fs, int list); +int codegen_codeABx(ktap_funcstate *fs, OpCode o, int a, unsigned int bc); +void codegen_ret(ktap_funcstate *fs, int first, int nret); +void codegen_exp2anyregup(ktap_funcstate *fs, ktap_expdesc *e); +void codegen_exp2val(ktap_funcstate *fs, ktap_expdesc *e); +int codegen_exp2RK(ktap_funcstate *fs, ktap_expdesc *e); +int codegen_codeABC(ktap_funcstate *fs, OpCode o, int a, int b, int c); +void codegen_setlist(ktap_funcstate *fs, int base, int nelems, int tostore); +void codegen_fixline (ktap_funcstate *fs, int line); +void codegen_dischargevars(ktap_funcstate *fs, ktap_expdesc *e); +void codegen_self(ktap_funcstate *fs, ktap_expdesc *e, ktap_expdesc *key); +void codegen_prefix(ktap_funcstate *fs, UnOpr op, ktap_expdesc *e, int line); +void codegen_infix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *v); +void codegen_posfix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *e1, ktap_expdesc *e2, int line); +void codegen_setoneret(ktap_funcstate *fs, ktap_expdesc *e); +void codegen_storevar(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex); +void codegen_storeincr(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex); +void codegen_goiftrue(ktap_funcstate *fs, ktap_expdesc *e); +int codegen_getlabel(ktap_funcstate *fs); +int codegen_codek(ktap_funcstate *fs, int reg, int k); +int codegen_numberK(ktap_funcstate *fs, ktap_number r); +void codegen_checkstack(ktap_funcstate *fs, int n); +void codegen_goiffalse(ktap_funcstate *fs, ktap_expdesc *e); +void codegen_concat(ktap_funcstate *fs, int *l1, int l2); +int codegen_exp2anyreg(ktap_funcstate *fs, ktap_expdesc *e); + +typedef int (*ktap_writer)(const void* p, size_t sz, void* ud); +int ktapc_dump(const ktap_proto *f, ktap_writer w, void *data, int strip); + +void ktapc_chunkid(char *out, const char *source, size_t bufflen); +int ktapc_str2d(const char *s, size_t len, ktap_number *result); +int ktapc_hexavalue(int c); +ktap_number ktapc_arith(int op, ktap_number v1, ktap_number v2); +int ktapc_int2fb(unsigned int x); + +bool strglobmatch(const char *str, const char *pat); + diff --git a/drivers/staging/ktap/userspace/ktapio.c b/drivers/staging/ktap/userspace/ktapio.c new file mode 100644 index 000000000000..f9bcab461f2a --- /dev/null +++ b/drivers/staging/ktap/userspace/ktapio.c @@ -0,0 +1,108 @@ +/* + * ktapio.c - ring buffer transport in userspace + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/poll.h> +#include <sys/signal.h> +#include <fcntl.h> +#include <pthread.h> + +#define MAX_BUFLEN 131072 +#define PATH_MAX 128 + +#define handle_error(str) do { perror(str); exit(-1); } while(0) + +extern pid_t ktap_pid; + +void sigfunc(int signo) +{ + /* should not not reach here */ +} + +static void block_sigint() +{ + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + + pthread_sigmask(SIG_BLOCK, &mask, NULL); +} + +static void *reader_thread(void *data) +{ + char buf[MAX_BUFLEN]; + char filename[PATH_MAX]; + const char *output = data; + int failed = 0, fd, out_fd, len; + + block_sigint(); + + if (output) { + out_fd = open(output, O_CREAT | O_WRONLY | O_TRUNC, + S_IRUSR|S_IWUSR); + if (out_fd < 0) { + fprintf(stderr, "Cannot open output file %s\n", output); + return NULL; + } + } else + out_fd = 2; + + sprintf(filename, "/sys/kernel/debug/ktap/trace_pipe_%d", ktap_pid); + + open_again: + fd = open(filename, O_RDONLY); + if (fd < 0) { + usleep(10000); + + if (failed++ == 10) { + fprintf(stderr, "Cannot open file %s\n", filename); + return NULL; + } + goto open_again; + } + + while ((len = read(fd, buf, sizeof(buf))) > 0) + write(out_fd, buf, len); + + close(fd); + close(out_fd); + + return NULL; +} + +int ktapio_create(const char *output) +{ + pthread_t reader; + + signal(SIGINT, sigfunc); + + if (pthread_create(&reader, NULL, reader_thread, (void *)output) < 0) + handle_error("pthread_create reader_thread failed\n"); + + return 0; +} + diff --git a/drivers/staging/ktap/userspace/lex.c b/drivers/staging/ktap/userspace/lex.c new file mode 100644 index 000000000000..484dd7fdafc3 --- /dev/null +++ b/drivers/staging/ktap/userspace/lex.c @@ -0,0 +1,622 @@ +/* + * lex.c - ktap lexical analyzer + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include "../include/ktap_types.h" +#include "ktapc.h" + +#define next(ls) (ls->current = *ls->ptr++) + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + +#define KTAP_MINBUFFER 32 + +/* ORDER RESERVED */ +static const char *const ktap_tokens [] = { + "trace", "trace_end", "argevent", "argname", + "arg1", "arg2", "arg3", "arg4", "arg5", "arg6", "arg7", "arg9", "arg9", + "profile", "tick", + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "goto", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "..", "...", "==", ">=", "<=", "!=", "+=", "::", "<eof>", + "<number>", "<name>", "<string>" +}; + +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + +static void lexerror(ktap_lexstate *ls, const char *msg, int token); + +static void save(ktap_lexstate *ls, int c) +{ + ktap_mbuffer *b = ls->buff; + if (mbuff_len(b) + 1 > mbuff_size(b)) { + size_t newsize; + if (mbuff_size(b) >= MAX_SIZET / 2) + lexerror(ls, "lexical element too long", 0); + newsize = mbuff_size(b) * 2; + mbuff_resize(b, newsize); + } + b->buffer[mbuff_len(b)++] = (char)c; +} + +void lex_init() +{ + int i; + for (i = 0; i < NUM_RESERVED; i++) { + ktap_string *ts = ktapc_ts_new(ktap_tokens[i]); + ts->tsv.extra = (u8)(i+1); /* reserved word */ + } +} + +const char *lex_token2str(ktap_lexstate *ls, int token) +{ + if (token < FIRST_RESERVED) { + ktap_assert(token == (unsigned char)token); + return (isprint(token)) ? ktapc_sprintf(KTAP_QL("%c"), token) : + ktapc_sprintf("char(%d)", token); + } else { + const char *s = ktap_tokens[token - FIRST_RESERVED]; + if (token < TK_EOS) + return ktapc_sprintf(KTAP_QS, s); + else + return s; + } +} + +static const char *txtToken(ktap_lexstate *ls, int token) +{ + switch (token) { + case TK_NAME: + case TK_STRING: + case TK_NUMBER: + save(ls, '\0'); + return ktapc_sprintf(KTAP_QS, mbuff(ls->buff)); + default: + return lex_token2str(ls, token); + } +} + +static void lexerror(ktap_lexstate *ls, const char *msg, int token) +{ + char buff[KTAP_IDSIZE]; + char *newmsg; + + ktapc_chunkid(buff, getstr(ls->source), KTAP_IDSIZE); + newmsg = ktapc_sprintf("%s:%d: %s", buff, ls->linenumber, msg); + if (token) + newmsg = ktapc_sprintf("%s near %s", newmsg, txtToken(ls, token)); + printf("lexerror: %s\n", newmsg); + exit(EXIT_FAILURE); +} + +void lex_syntaxerror(ktap_lexstate *ls, const char *msg) +{ + lexerror(ls, msg, ls->t.token); +} + +/* + * creates a new string and anchors it in function's table so that + * it will not be collected until the end of the function's compilation + * (by that time it should be anchored in function's prototype) + */ +ktap_string *lex_newstring(ktap_lexstate *ls, const char *str, size_t l) +{ + const ktap_value *o; /* entry for `str' */ + ktap_value val; /* entry for `str' */ + ktap_value tsv; + ktap_string *ts = ktapc_ts_newlstr(str, l); /* create new string */ + setsvalue(&tsv, ts); + o = ktapc_table_get(ls->fs->h, &tsv); + if (ttisnil(o)) { /* not in use yet? (see 'addK') */ + /* boolean value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setbvalue(&val, 1); /* t[string] = true */ + ktapc_table_setvalue(ls->fs->h, &tsv, &val); + } + return ts; +} + +/* + * increment line number and skips newline sequence (any of + * \n, \r, \n\r, or \r\n) + */ +static void inclinenumber(ktap_lexstate *ls) +{ + int old = ls->current; + ktap_assert(currIsNewline(ls)); + next(ls); /* skip `\n' or `\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip `\n\r' or `\r\n' */ + if (++ls->linenumber >= MAX_INT) + lex_syntaxerror(ls, "chunk has too many lines"); +} + +void lex_setinput(ktap_lexstate *ls, char *ptr, ktap_string *source, int firstchar) +{ + ls->decpoint = '.'; + ls->current = firstchar; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->ptr = ptr; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + ls->envn = ktapc_ts_new(KTAP_ENV); /* create env name */ + mbuff_resize(ls->buff, KTAP_MINBUFFER); /* initialize buffer */ +} + +/* + * ======================================================= + * LEXICAL ANALYZER + * ======================================================= + */ +static int check_next(ktap_lexstate *ls, const char *set) +{ + if (ls->current == '\0' || !strchr(set, ls->current)) + return 0; + save_and_next(ls); + return 1; +} + +/* + * change all characters 'from' in buffer to 'to' + */ +static void buffreplace(ktap_lexstate *ls, char from, char to) +{ + size_t n = mbuff_len(ls->buff); + char *p = mbuff(ls->buff); + while (n--) + if (p[n] == from) p[n] = to; +} + +#if !defined(getlocaledecpoint) +#define getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + +#define mbuff2d(b,e) ktapc_str2d(mbuff(b), mbuff_len(b) - 1, e) + +/* + * in case of format error, try to change decimal point separator to + * the one defined in the current locale and check again + */ +static void trydecpoint(ktap_lexstate *ls, ktap_seminfo *seminfo) +{ + char old = ls->decpoint; + ls->decpoint = getlocaledecpoint(); + buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ + if (!mbuff2d(ls->buff, &seminfo->r)) { + /* format error with correct decimal point: no more options */ + buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ + lexerror(ls, "malformed number", TK_NUMBER); + } +} + +/* + * this function is quite liberal in what it accepts, as 'ktapc_str2d' + * will reject ill-formed numerals. + */ +static void read_numeral(ktap_lexstate *ls, ktap_seminfo *seminfo) +{ + const char *expo = "Ee"; + int first = ls->current; + + ktap_assert(isdigit(ls->current)); + save_and_next(ls); + if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ + expo = "Pp"; + for (;;) { + if (check_next(ls, expo)) /* exponent part? */ + check_next(ls, "+-"); /* optional exponent sign */ + if (isxdigit(ls->current) || ls->current == '.') + save_and_next(ls); + else + break; + } + save(ls, '\0'); + buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ + if (!mbuff2d(ls->buff, &seminfo->r)) /* format error? */ + trydecpoint(ls, seminfo); /* try to update decimal point separator */ +} + +/* + * skip a sequence '[=*[' or ']=*]' and return its number of '='s or + * -1 if sequence is malformed + */ +static int skip_sep(ktap_lexstate *ls) +{ + int count = 0; + int s = ls->current; + + ktap_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count : (-count) - 1; +} + +static void read_long_string(ktap_lexstate *ls, ktap_seminfo *seminfo, int sep) +{ + save_and_next(ls); /* skip 2nd `[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls->current) { + case EOZ: + lexerror(ls, (seminfo) ? "unfinished long string" : + "unfinished long comment", TK_EOS); + break; /* to avoid warnings */ + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `]' */ + goto endloop; + } + break; + } + case '\n': + case '\r': { + save(ls, '\n'); + inclinenumber(ls); + /* avoid wasting space */ + if (!seminfo) + mbuff_reset(ls->buff); + break; + } + default: { + if (seminfo) + save_and_next(ls); + else + next(ls); + } + } + } + + endloop: + if (seminfo) + seminfo->ts = lex_newstring(ls, mbuff(ls->buff) + (2 + sep), + mbuff_len(ls->buff) - 2*(2 + sep)); +} + +static void escerror(ktap_lexstate *ls, int *c, int n, const char *msg) +{ + int i; + mbuff_reset(ls->buff); /* prepare error message */ + save(ls, '\\'); + for (i = 0; i < n && c[i] != EOZ; i++) + save(ls, c[i]); + lexerror(ls, msg, TK_STRING); +} + +static int readhexaesc(ktap_lexstate *ls) +{ + int c[3], i; /* keep input for error message */ + int r = 0; /* result accumulator */ + c[0] = 'x'; /* for error message */ + for (i = 1; i < 3; i++) { /* read two hexa digits */ + c[i] = next(ls); + if (!isxdigit(c[i])) + escerror(ls, c, i + 1, "hexadecimal digit expected"); + r = (r << 4) + ktapc_hexavalue(c[i]); + } + return r; +} + +static int readdecesc(ktap_lexstate *ls) +{ + int c[3], i; + int r = 0; /* result accumulator */ + for (i = 0; i < 3 && isdigit(ls->current); i++) { /* read up to 3 digits */ + c[i] = ls->current; + r = 10*r + c[i] - '0'; + next(ls); + } + if (r > UCHAR_MAX) + escerror(ls, c, i, "decimal escape too large"); + return r; +} + +static void read_string(ktap_lexstate *ls, int del, ktap_seminfo *seminfo) +{ + save_and_next(ls); /* keep delimiter (for error messages) */ + while (ls->current != del) { + switch (ls->current) { + case EOZ: + lexerror(ls, "unfinished string", TK_EOS); + break; /* to avoid warnings */ + case '\n': + case '\r': + lexerror(ls, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': { /* escape sequences */ + int c; /* final character to be saved */ + next(ls); /* do not save the `\' */ + switch (ls->current) { + case 'a': c = '\a'; goto read_save; + case 'b': c = '\b'; goto read_save; + case 'f': c = '\f'; goto read_save; + case 'n': c = '\n'; goto read_save; + case 'r': c = '\r'; goto read_save; + case 't': c = '\t'; goto read_save; + case 'v': c = '\v'; goto read_save; + case 'x': c = readhexaesc(ls); goto read_save; + case '\n': case '\r': + inclinenumber(ls); c = '\n'; goto only_save; + case '\\': case '\"': case '\'': + c = ls->current; goto read_save; + case EOZ: goto no_save; /* will raise an error next loop */ + case 'z': { /* zap following span of spaces */ + next(ls); /* skip the 'z' */ + while (isspace(ls->current)) { + if (currIsNewline(ls)) + inclinenumber(ls); + else + next(ls); + } + goto no_save; + } + default: { + if (!isdigit(ls->current)) + escerror(ls, &ls->current, 1, "invalid escape sequence"); + /* digital escape \ddd */ + c = readdecesc(ls); + goto only_save; + } + } + read_save: + next(ls); /* read next character */ + only_save: + save(ls, c); /* save 'c' */ + no_save: + break; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = lex_newstring(ls, mbuff(ls->buff) + 1, mbuff_len(ls->buff) - 2); +} + +static int llex(ktap_lexstate *ls, ktap_seminfo *seminfo) +{ + mbuff_reset(ls->buff); + + for (;;) { + switch (ls->current) { + case '\n': case '\r': { /* line breaks */ + inclinenumber(ls); + break; + } + case ' ': case '\f': case '\t': case '\v': { /* spaces */ + next(ls); + break; + } + case '#': { + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); /* skip until end of line (or end of file) */ + break; + } + #if 0 + case '-': { /* '-' or '--' (comment) */ + next(ls); + if (ls->current != '-') + return '-'; + /* else is a comment */ + next(ls); + if (ls->current == '[') { /* long comment? */ + int sep = skip_sep(ls); + mbuff_reset(ls->buff); /* `skip_sep' may dirty the buffer */ + if (sep >= 0) { + read_long_string(ls, NULL, sep); /* skip long comment */ + mbuff_reset(ls->buff); /* previous call may dirty the buff. */ + break; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); /* skip until end of line (or end of file) */ + break; + } + #endif + case '[': { /* long string or simply '[' */ + int sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep == -1) + return '['; + else + lexerror(ls, "invalid long string delimiter", TK_STRING); + } + case '+': { + next(ls); + if (ls->current != '=') + return '+'; + else { + next(ls); + return TK_INCR; + } + } + case '=': { + next(ls); + if (ls->current != '=') + return '='; + else { + next(ls); + return TK_EQ; + } + } + case '<': { + next(ls); + if (ls->current != '=') + return '<'; + else { + next(ls); + return TK_LE; + } + } + case '>': { + next(ls); + if (ls->current != '=') + return '>'; + else { + next(ls); + return TK_GE; + } + } + case '!': { + next(ls); + if (ls->current != '=') + return TK_NOT; + else { + next(ls); + return TK_NE; + } + } + case ':': { + next(ls); + if (ls->current != ':') + return ':'; + else { + next(ls); + return TK_DBCOLON; + } + } + case '"': case '\'': { /* short literal strings */ + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': { /* '.', '..', '...', or number */ + save_and_next(ls); + if (check_next(ls, ".")) { + if (check_next(ls, ".")) + return TK_DOTS; /* '...' */ + else + return TK_CONCAT; /* '..' */ + } + else if (!isdigit(ls->current)) + return '.'; + /* else go through */ + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + read_numeral(ls, seminfo); + return TK_NUMBER; + } + case EOZ: { + return TK_EOS; + } + case '&': { + next(ls); + if (ls->current != '&') + return '&'; + else { + next(ls); + return TK_AND; + } + } + case '|': { + next(ls); + if (ls->current != '|') + return '|'; + else { + next(ls); + return TK_OR; + } + } + default: { + if (islalpha(ls->current)) { + /* identifier or reserved word? */ + ktap_string *ts; + do { + save_and_next(ls); + } while (islalnum(ls->current)); + ts = lex_newstring(ls, mbuff(ls->buff), + mbuff_len(ls->buff)); + seminfo->ts = ts; + if (isreserved(ts)) /* reserved word? */ + return ts->tsv.extra - 1 + + FIRST_RESERVED; + else { + return TK_NAME; + } + } else { /* single-char tokens (+ - / ...) */ + int c = ls->current; + next(ls); + return c; + } + } + } + } +} + +void lex_read_string_until(ktap_lexstate *ls, int c) +{ + ktap_string *ts; + char errmsg[32]; + + mbuff_reset(ls->buff); + + while (ls->current == ' ') + next(ls); + + do { + save_and_next(ls); + } while (ls->current != c && ls->current != EOZ); + + if (ls->current != c) { + sprintf(errmsg, "expect %c", c); + lexerror(ls, errmsg, 0); + } + + ts = lex_newstring(ls, mbuff(ls->buff), mbuff_len(ls->buff)); + ls->t.seminfo.ts = ts; + ls->t.token = TK_STRING; +} + +void lex_next(ktap_lexstate *ls) +{ + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + +int lex_lookahead(ktap_lexstate *ls) +{ + ktap_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); + return ls->lookahead.token; +} + diff --git a/drivers/staging/ktap/userspace/main.c b/drivers/staging/ktap/userspace/main.c new file mode 100644 index 000000000000..2aa686a99914 --- /dev/null +++ b/drivers/staging/ktap/userspace/main.c @@ -0,0 +1,609 @@ +/* + * main.c - ktap compiler and loader entry + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sched.h> +#include <string.h> +#include <signal.h> +#include <stdarg.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <math.h> + +#include "../include/ktap_types.h" +#include "../include/ktap_opcodes.h" +#include "ktapc.h" + + +/*******************************************************************/ + +void *ktapc_reallocv(void *block, size_t osize, size_t nsize) +{ + return kp_reallocv(NULL, block, osize, nsize); +} + +ktap_closure *ktapc_newlclosure(int n) +{ + return kp_newlclosure(NULL, n); +} + +ktap_proto *ktapc_newproto() +{ + return kp_newproto(NULL); +} + +const ktap_value *ktapc_table_get(ktap_table *t, const ktap_value *key) +{ + return kp_table_get(t, key); +} + +void ktapc_table_setvalue(ktap_table *t, const ktap_value *key, ktap_value *val) +{ + kp_table_setvalue(NULL, t, key, val); +} + +ktap_table *ktapc_table_new() +{ + return kp_table_new(NULL); +} + +ktap_string *ktapc_ts_newlstr(const char *str, size_t l) +{ + return kp_tstring_newlstr(NULL, str, l); +} + +ktap_string *ktapc_ts_new(const char *str) +{ + return kp_tstring_new(NULL, str); +} + +int ktapc_ts_eqstr(ktap_string *a, ktap_string *b) +{ + return kp_tstring_eqstr(a, b); +} + +static void ktapc_runerror(const char *err_msg_fmt, ...) +{ + va_list ap; + + fprintf(stderr, "ktapc_runerror\n"); + + va_start(ap, err_msg_fmt); + vfprintf(stderr, err_msg_fmt, ap); + va_end(ap); + + exit(EXIT_FAILURE); +} + +/* + * todo: memory leak here + */ +char *ktapc_sprintf(const char *fmt, ...) +{ + char *msg = malloc(128); + + va_list argp; + va_start(argp, fmt); + vsprintf(msg, fmt, argp); + va_end(argp); + return msg; +} + + +#define MINSIZEARRAY 4 + +void *ktapc_growaux(void *block, int *size, size_t size_elems, int limit, + const char *what) +{ + void *newblock; + int newsize; + + if (*size >= limit/2) { /* cannot double it? */ + if (*size >= limit) /* cannot grow even a little? */ + ktapc_runerror("too many %s (limit is %d)\n", + what, limit); + newsize = limit; /* still have at least one free place */ + } else { + newsize = (*size) * 2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + } + + newblock = ktapc_reallocv(block, (*size) * size_elems, newsize * size_elems); + *size = newsize; /* update only when everything else is OK */ + return newblock; +} + +/*************************************************************************/ + +#define print_base(i) \ + do { \ + if (i < f->sizelocvars) /* it's a localvars */ \ + printf("%s", getstr(f->locvars[i].varname)); \ + else \ + printf("base + %d", i); \ + } while (0) + +#define print_RKC(instr) \ + do { \ + if (ISK(GETARG_C(instr))) \ + kp_showobj(NULL, k + INDEXK(GETARG_C(instr))); \ + else \ + print_base(GETARG_C(instr)); \ + } while (0) + +static void decode_instruction(ktap_proto *f, int instr) +{ + int opcode = GET_OPCODE(instr); + ktap_value *k; + + k = f->k; + + printf("%.8x\t", instr); + printf("%s\t", ktap_opnames[opcode]); + + switch (opcode) { + case OP_GETTABUP: + print_base(GETARG_A(instr)); + printf(" <- "); + + if (GETARG_B(instr) == 0) + printf("global"); + else + printf("upvalues[%d]", GETARG_B(instr)); + + printf("{"); print_RKC(instr); printf("}"); + + break; + case OP_GETTABLE: + print_base(GETARG_A(instr)); + printf(" <- "); + + print_base(GETARG_B(instr)); + + printf("{"); + print_RKC(instr); + printf("}"); + break; + case OP_LOADK: + printf("\t"); + print_base(GETARG_A(instr)); + printf(" <- "); + + kp_showobj(NULL, k + GETARG_Bx(instr)); + break; + case OP_CALL: + printf("\t"); + print_base(GETARG_A(instr)); + break; + case OP_JMP: + printf("\t%d", GETARG_sBx(instr)); + break; + default: + break; + } + + printf("\n"); +} + +static int function_nr = 0; + +/* this is a debug function used for check bytecode chunk file */ +static void dump_function(int level, ktap_proto *f) +{ + int i; + + printf("\n----------------------------------------------------\n"); + printf("function %d [level %d]:\n", function_nr++, level); + printf("linedefined: %d\n", f->linedefined); + printf("lastlinedefined: %d\n", f->lastlinedefined); + printf("numparams: %d\n", f->numparams); + printf("is_vararg: %d\n", f->is_vararg); + printf("maxstacksize: %d\n", f->maxstacksize); + printf("source: %s\n", getstr(f->source)); + printf("sizelineinfo: %d \t", f->sizelineinfo); + for (i = 0; i < f->sizelineinfo; i++) + printf("%d ", f->lineinfo[i]); + printf("\n"); + + printf("sizek: %d\n", f->sizek); + for (i = 0; i < f->sizek; i++) { + switch(f->k[i].type) { + case KTAP_TNIL: + printf("\tNIL\n"); + break; + case KTAP_TBOOLEAN: + printf("\tBOOLEAN: "); + printf("%d\n", f->k[i].val.b); + break; + case KTAP_TNUMBER: + printf("\tTNUMBER: "); + printf("%ld\n", f->k[i].val.n); + break; + case KTAP_TSTRING: + printf("\tTSTRING: "); + printf("%s\n", svalue(&(f->k[i]))); + + break; + default: + printf("\terror: unknow constant type\n"); + } + } + + printf("sizelocvars: %d\n", f->sizelocvars); + for (i = 0; i < f->sizelocvars; i++) { + printf("\tlocvars: %s startpc: %d endpc: %d\n", + getstr(f->locvars[i].varname), f->locvars[i].startpc, + f->locvars[i].endpc); + } + + printf("sizeupvalues: %d\n", f->sizeupvalues); + for (i = 0; i < f->sizeupvalues; i++) { + printf("\tname: %s instack: %d idx: %d\n", + getstr(f->upvalues[i].name), f->upvalues[i].instack, + f->upvalues[i].idx); + } + + printf("\n"); + printf("sizecode: %d\n", f->sizecode); + for (i = 0; i < f->sizecode; i++) + decode_instruction(f, f->code[i]); + + printf("sizep: %d\n", f->sizep); + for (i = 0; i < f->sizep; i++) + dump_function(level + 1, f->p[i]); + +} + +static void usage(const char *msg_fmt, ...) +{ + va_list ap; + + va_start(ap, msg_fmt); + fprintf(stderr, msg_fmt, ap); + va_end(ap); + + fprintf(stderr, +"Usage: ktap [options] file [script args] -- cmd [args]\n" +" or: ktap [options] -e one-liner -- cmd [args]\n" +"\n" +"Options and arguments:\n" +" -o file : send script output to file, instead of stderr\n" +" -p pid : specific tracing pid\n" +" -C cpu : cpu to monitor in system-wide\n" +" -T : show timestamp for event\n" +" -V : show version\n" +" -v : enable verbose mode\n" +" -s : simple event tracing\n" +" -b : list byte codes\n" +" file : program read from script file\n" +" -- cmd [args] : workload to tracing\n"); + + exit(EXIT_FAILURE); +} + +ktap_global_state dummy_global_state; + +static void init_dummy_global_state() +{ + memset(&dummy_global_state, 0, sizeof(ktap_global_state)); + dummy_global_state.seed = 201236; + + kp_tstring_resize(NULL, 32); /* set inital string hashtable size */ +} + +#define handle_error(str) do { perror(str); exit(-1); } while(0) + +static struct ktap_parm uparm; +static int ktap_trunk_mem_size = 1024; + +static int ktapc_writer(const void* p, size_t sz, void* ud) +{ + if (uparm.trunk_len + sz > ktap_trunk_mem_size) { + int new_size = (uparm.trunk_len + sz) * 2; + uparm.trunk = realloc(uparm.trunk, new_size); + ktap_trunk_mem_size = new_size; + } + + memcpy(uparm.trunk + uparm.trunk_len, p, sz); + uparm.trunk_len += sz; + + return 0; +} + + +static int forks; +static char **workload_argv; + +static int fork_workload(int ktap_fd) +{ + int pid; + + pid = fork(); + if (pid < 0) + handle_error("failed to fork"); + + if (pid > 0) + return pid; + + signal(SIGTERM, SIG_DFL); + + execvp("", workload_argv); + + /* + * waiting ktapvm prepare all tracing event + * make it more robust in future. + */ + pause(); + + execvp(workload_argv[0], workload_argv); + + perror(workload_argv[0]); + exit(-1); + + return -1; +} + +#define KTAPVM_PATH "/sys/kernel/debug/ktap/ktapvm" + +static char *output_filename; +pid_t ktap_pid; + +static int run_ktapvm() +{ + int ktapvm_fd, ktap_fd; + int ret; + + ktap_pid = getpid(); + + ktapvm_fd = open(KTAPVM_PATH, O_RDONLY); + if (ktapvm_fd < 0) + handle_error("open " KTAPVM_PATH " failed"); + + ktap_fd = ioctl(ktapvm_fd, 0, NULL); + if (ktap_fd < 0) + handle_error("ioctl ktapvm failed"); + + ktapio_create(output_filename); + + if (forks) { + uparm.trace_pid = fork_workload(ktap_fd); + uparm.workload = 1; + } + + ret = ioctl(ktap_fd, KTAP_CMD_IOC_RUN, &uparm); + + close(ktap_fd); + close(ktapvm_fd); + + return ret; +} + +int verbose; +static int dump_bytecode; +static char oneline_src[1024]; +static int trace_pid = -1; +static int trace_cpu = -1; +static int print_timestamp; + +#define SIMPLE_ONE_LINER_FMT \ + "trace %s { print(cpu(), tid(), execname(), argevent) }" + +static const char *script_file; +static int script_args_start; +static int script_args_end; + +static void parse_option(int argc, char **argv) +{ + char pid[32] = {0}; + char cpu_str[32] = {0}; + char *next_arg; + int i, j; + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + script_file = argv[i]; + if (!script_file) + usage(""); + + script_args_start = i + 1; + script_args_end = argc; + + for (j = i + 1; j < argc; j++) { + if (argv[j][0] == '-' && argv[j][1] == '-') + goto found_cmd; + } + + return; + } + + if (argv[i][0] == '-' && argv[i][1] == '-') { + j = i; + goto found_cmd; + } + + next_arg = argv[i + 1]; + + switch (argv[i][1]) { + case 'o': + output_filename = malloc(strlen(next_arg) + 1); + if (!output_filename) + return; + + strncpy(output_filename, next_arg, strlen(next_arg)); + i++; + break; + case 'e': + strncpy(oneline_src, next_arg, strlen(next_arg)); + i++; + break; + case 'p': + strncpy(pid, next_arg, strlen(next_arg)); + trace_pid = atoi(pid); + i++; + break; + case 'C': + strncpy(cpu_str, next_arg, strlen(next_arg)); + trace_cpu = atoi(cpu_str); + i++; + break; + case 'T': + print_timestamp = 1; + break; + case 'v': + verbose = 1; + break; + case 's': + sprintf(oneline_src, SIMPLE_ONE_LINER_FMT, next_arg); + i++; + break; + case 'b': + dump_bytecode = 1; + break; + case 'V': + case '?': + case 'h': + usage(""); + break; + default: + usage("wrong argument\n"); + break; + } + } + + return; + + found_cmd: + script_args_end = j; + forks = 1; + workload_argv = &argv[j + 1]; +} + +static void compile(const char *input) +{ + ktap_closure *cl; + char *buff; + struct stat sb; + int fdin; + + if (oneline_src[0] != '\0') { + init_dummy_global_state(); + cl = ktapc_parser(oneline_src, input); + goto dump; + } + + fdin = open(input, O_RDONLY); + if (fdin < 0) { + fprintf(stderr, "open file %s failed\n", input); + exit(-1); + } + + if (fstat(fdin, &sb) == -1) + handle_error("fstat failed"); + + buff = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fdin, 0); + if (buff == MAP_FAILED) + handle_error("mmap failed"); + + init_dummy_global_state(); + cl = ktapc_parser(buff, input); + + munmap(buff, sb.st_size); + close(fdin); + + dump: + if (dump_bytecode) { + dump_function(1, cl->l.p); + exit(0); + } + + /* ktapc output */ + uparm.trunk = malloc(ktap_trunk_mem_size); + if (!uparm.trunk) + handle_error("malloc failed"); + + ktapc_dump(cl->l.p, ktapc_writer, NULL, 0); +} + +int main(int argc, char **argv) +{ + char **ktapvm_argv; + int new_index, i; + int ret; + + if (argc == 1) + usage(""); + + parse_option(argc, argv); + + if (oneline_src[0] != '\0') + script_file = "one-liner"; + + compile(script_file); + + ktapvm_argv = (char **)malloc(sizeof(char *)*(script_args_end - + script_args_start + 1)); + if (!ktapvm_argv) { + fprintf(stderr, "canno allocate ktapvm_argv\n"); + return -1; + } + + ktapvm_argv[0] = malloc(strlen(script_file) + 1); + if (!ktapvm_argv[0]) { + fprintf(stderr, "canno allocate memory\n"); + return -1; + } + strcpy(ktapvm_argv[0], script_file); + ktapvm_argv[0][strlen(script_file)] = '\0'; + + /* pass rest argv into ktapvm */ + new_index = 1; + for (i = script_args_start; i < script_args_end; i++) { + ktapvm_argv[new_index] = malloc(strlen(argv[i]) + 1); + if (!ktapvm_argv[new_index]) { + fprintf(stderr, "canno allocate memory\n"); + return -1; + } + strcpy(ktapvm_argv[new_index], argv[i]); + ktapvm_argv[new_index][strlen(argv[i])] = '\0'; + new_index++; + } + + uparm.argv = ktapvm_argv; + uparm.argc = new_index; + uparm.verbose = verbose; + uparm.trace_pid = trace_pid; + uparm.trace_cpu = trace_cpu; + uparm.print_timestamp = print_timestamp; + + /* start running into kernel ktapvm */ + ret = run_ktapvm(); + + cleanup_event_resources(); + return ret; +} + + diff --git a/drivers/staging/ktap/userspace/parser.c b/drivers/staging/ktap/userspace/parser.c new file mode 100644 index 000000000000..dd9e2de692ad --- /dev/null +++ b/drivers/staging/ktap/userspace/parser.c @@ -0,0 +1,1910 @@ +/* + * parser.c - ktap parser + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../include/ktap_types.h" +#include "../include/ktap_opcodes.h" +#include "ktapc.h" + +/* maximum number of local variables per function (must be smaller + than 250, due to the bytecode format) */ +#define MAXVARS 200 + +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + + +/* + * nodes for block list (list of active blocks) + */ +typedef struct ktap_blockcnt { + struct ktap_blockcnt *previous; /* chain */ + short firstlabel; /* index of first label in this block */ + short firstgoto; /* index of first pending goto in this block */ + u8 nactvar; /* # active locals outside the block */ + u8 upval; /* true if some variable in the block is an upvalue */ + u8 isloop; /* true if `block' is a loop */ +} ktap_blockcnt; + +/* + * prototypes for recursive non-terminal functions + */ +static void statement (ktap_lexstate *ls); +static void expr (ktap_lexstate *ls, ktap_expdesc *v); + +static void anchor_token(ktap_lexstate *ls) +{ + /* last token from outer function must be EOS */ + ktap_assert((int)(ls->fs != NULL) || ls->t.token == TK_EOS); + if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { + ktap_string *ts = ls->t.seminfo.ts; + lex_newstring(ls, getstr(ts), ts->tsv.len); + } +} + +/* semantic error */ +static void semerror(ktap_lexstate *ls, const char *msg) +{ + ls->t.token = 0; /* remove 'near to' from final message */ + lex_syntaxerror(ls, msg); +} + +static void error_expected(ktap_lexstate *ls, int token) +{ + lex_syntaxerror(ls, + ktapc_sprintf("%s expected", lex_token2str(ls, token))); +} + +static void errorlimit(ktap_funcstate *fs, int limit, const char *what) +{ + const char *msg; + int line = fs->f->linedefined; + const char *where = (line == 0) ? "main function" + : ktapc_sprintf("function at line %d", line); + + msg = ktapc_sprintf("too many %s (limit is %d) in %s", + what, limit, where); + lex_syntaxerror(fs->ls, msg); +} + +static void checklimit(ktap_funcstate *fs, int v, int l, const char *what) +{ + if (v > l) + errorlimit(fs, l, what); +} + +static int testnext(ktap_lexstate *ls, int c) +{ + if (ls->t.token == c) { + lex_next(ls); + return 1; + } + else + return 0; +} + +static void check(ktap_lexstate *ls, int c) +{ + if (ls->t.token != c) + error_expected(ls, c); +} + +static void checknext(ktap_lexstate *ls, int c) +{ + check(ls, c); + lex_next(ls); +} + +#define check_condition(ls,c,msg) { if (!(c)) lex_syntaxerror(ls, msg); } + +static void check_match(ktap_lexstate *ls, int what, int who, int where) +{ + if (!testnext(ls, what)) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + lex_syntaxerror(ls, ktapc_sprintf( + "%s expected (to close %s at line %d)", + lex_token2str(ls, what), + lex_token2str(ls, who), where)); + } + } +} + +static ktap_string *str_checkname(ktap_lexstate *ls) +{ + ktap_string *ts; + + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + lex_next(ls); + return ts; +} + +static void init_exp(ktap_expdesc *e, expkind k, int i) +{ + e->f = e->t = NO_JUMP; + e->k = k; + e->u.info = i; +} + +static void codestring(ktap_lexstate *ls, ktap_expdesc *e, ktap_string *s) +{ + init_exp(e, VK, codegen_stringK(ls->fs, s)); +} + +static void checkname(ktap_lexstate *ls, ktap_expdesc *e) +{ + codestring(ls, e, str_checkname(ls)); +} + +static int registerlocalvar(ktap_lexstate *ls, ktap_string *varname) +{ + ktap_funcstate *fs = ls->fs; + ktap_proto *f = fs->f; + int oldsize = f->sizelocvars; + + ktapc_growvector(f->locvars, fs->nlocvars, f->sizelocvars, + ktap_locvar, SHRT_MAX, "local variables"); + + while (oldsize < f->sizelocvars) + f->locvars[oldsize++].varname = NULL; + + f->locvars[fs->nlocvars].varname = varname; + return fs->nlocvars++; +} + +static void new_localvar(ktap_lexstate *ls, ktap_string *name) +{ + ktap_funcstate *fs = ls->fs; + ktap_dyndata *dyd = ls->dyd; + int reg = registerlocalvar(ls, name); + + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, + MAXVARS, "local variables"); + ktapc_growvector(dyd->actvar.arr, dyd->actvar.n + 1, + dyd->actvar.size, ktap_vardesc, MAX_INT, "local variables"); + dyd->actvar.arr[dyd->actvar.n++].idx = (short)reg; +} + +static void new_localvarliteral_(ktap_lexstate *ls, const char *name, size_t sz) +{ + new_localvar(ls, lex_newstring(ls, name, sz)); +} + +#define new_localvarliteral(ls,v) \ + new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) + +static ktap_locvar *getlocvar(ktap_funcstate *fs, int i) +{ + int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; + + ktap_assert(idx < fs->nlocvars); + return &fs->f->locvars[idx]; +} + +static void adjustlocalvars(ktap_lexstate *ls, int nvars) +{ + ktap_funcstate *fs = ls->fs; + + fs->nactvar = (u8)(fs->nactvar + nvars); + for (; nvars; nvars--) { + getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; + } +} + +static void removevars(ktap_funcstate *fs, int tolevel) +{ + fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); + + while (fs->nactvar > tolevel) + getlocvar(fs, --fs->nactvar)->endpc = fs->pc; +} + +static int searchupvalue(ktap_funcstate *fs, ktap_string *name) +{ + int i; + ktap_upvaldesc *up = fs->f->upvalues; + + for (i = 0; i < fs->nups; i++) { + if (ktapc_ts_eqstr(up[i].name, name)) + return i; + } + return -1; /* not found */ +} + +static int newupvalue(ktap_funcstate *fs, ktap_string *name, ktap_expdesc *v) +{ + ktap_proto *f = fs->f; + int oldsize = f->sizeupvalues; + + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + ktapc_growvector(f->upvalues, fs->nups, f->sizeupvalues, + ktap_upvaldesc, MAXUPVAL, "upvalues"); + + while (oldsize < f->sizeupvalues) + f->upvalues[oldsize++].name = NULL; + f->upvalues[(int)fs->nups].instack = (v->k == VLOCAL); + f->upvalues[(int)fs->nups].idx = (u8)(v->u.info); + f->upvalues[(int)fs->nups].name = name; + return fs->nups++; +} + +static int searchvar(ktap_funcstate *fs, ktap_string *n) +{ + int i; + + for (i = fs->nactvar-1; i >= 0; i--) { + if (ktapc_ts_eqstr(n, getlocvar(fs, i)->varname)) + return i; + } + return -1; /* not found */ +} + +/* + * Mark block where variable at given level was defined + * (to emit close instructions later). + */ +static void markupval(ktap_funcstate *fs, int level) +{ + ktap_blockcnt *bl = fs->bl; + + while (bl->nactvar > level) + bl = bl->previous; + bl->upval = 1; +} + +/* + * Find variable with given name 'n'. If it is an upvalue, add this + * upvalue into all intermediate functions. + */ +static int singlevaraux(ktap_funcstate *fs, ktap_string *n, ktap_expdesc *var, int base) +{ + if (fs == NULL) /* no more levels? */ + return VVOID; /* default is global */ + else { + int v = searchvar(fs, n); /* look up locals at current level */ + if (v >= 0) { /* found? */ + init_exp(var, VLOCAL, v); /* variable is local */ + if (!base) + markupval(fs, v); /* local will be used as an upval */ + return VLOCAL; + } else { /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) { /* not found? */ + if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ + return VVOID; /* not found; is a global */ + /* else was LOCAL or UPVAL */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + } + init_exp(var, VUPVAL, idx); + return VUPVAL; + } + } +} + +static void singlevar(ktap_lexstate *ls, ktap_expdesc *var) +{ + ktap_string *varname = str_checkname(ls); + ktap_funcstate *fs = ls->fs; + + if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ + ktap_expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ + ktap_assert(var->k == VLOCAL || var->k == VUPVAL); + codestring(ls, &key, varname); /* key is variable name */ + codegen_indexed(fs, var, &key); /* env[varname] */ + } +} + +static void adjust_assign(ktap_lexstate *ls, int nvars, int nexps, ktap_expdesc *e) +{ + ktap_funcstate *fs = ls->fs; + int extra = nvars - nexps; + + if (hasmultret(e->k)) { + extra++; /* includes call itself */ + if (extra < 0) + extra = 0; + codegen_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) + codegen_reserveregs(fs, extra-1); + } else { + if (e->k != VVOID) + codegen_exp2nextreg(fs, e); /* close last expression */ + if (extra > 0) { + int reg = fs->freereg; + + codegen_reserveregs(fs, extra); + codegen_nil(fs, reg, extra); + } + } +} + +static void enterlevel(ktap_lexstate *ls) +{ + ++ls->nCcalls; + checklimit(ls->fs, ls->nCcalls, KTAP_MAXCCALLS, "C levels"); +} + +static void closegoto(ktap_lexstate *ls, int g, ktap_labeldesc *label) +{ + int i; + ktap_funcstate *fs = ls->fs; + ktap_labellist *gl = &ls->dyd->gt; + ktap_labeldesc *gt = &gl->arr[g]; + + ktap_assert(ktapc_ts_eqstr(gt->name, label->name)); + if (gt->nactvar < label->nactvar) { + ktap_string *vname = getlocvar(fs, gt->nactvar)->varname; + const char *msg = ktapc_sprintf( + "<goto %s> at line %d jumps into the scope of local " KTAP_QS, + getstr(gt->name), gt->line, getstr(vname)); + semerror(ls, msg); + } + + codegen_patchlist(fs, gt->pc, label->pc); + /* remove goto from pending list */ + for (i = g; i < gl->n - 1; i++) + gl->arr[i] = gl->arr[i + 1]; + gl->n--; +} + +/* + * try to close a goto with existing labels; this solves backward jumps + */ +static int findlabel(ktap_lexstate *ls, int g) +{ + int i; + ktap_blockcnt *bl = ls->fs->bl; + ktap_dyndata *dyd = ls->dyd; + ktap_labeldesc *gt = &dyd->gt.arr[g]; + + /* check labels in current block for a match */ + for (i = bl->firstlabel; i < dyd->label.n; i++) { + ktap_labeldesc *lb = &dyd->label.arr[i]; + if (ktapc_ts_eqstr(lb->name, gt->name)) { /* correct label? */ + if (gt->nactvar > lb->nactvar && + (bl->upval || dyd->label.n > bl->firstlabel)) + codegen_patchclose(ls->fs, gt->pc, lb->nactvar); + closegoto(ls, g, lb); /* close it */ + return 1; + } + } + return 0; /* label not found; cannot close goto */ +} + +static int newlabelentry(ktap_lexstate *ls, ktap_labellist *l, ktap_string *name, + int line, int pc) +{ + int n = l->n; + + ktapc_growvector(l->arr, n, l->size, + ktap_labeldesc, SHRT_MAX, "labels/gotos"); + l->arr[n].name = name; + l->arr[n].line = line; + l->arr[n].nactvar = ls->fs->nactvar; + l->arr[n].pc = pc; + l->n++; + return n; +} + + +/* + * check whether new label 'lb' matches any pending gotos in current + * block; solves forward jumps + */ +static void findgotos(ktap_lexstate *ls, ktap_labeldesc *lb) +{ + ktap_labellist *gl = &ls->dyd->gt; + int i = ls->fs->bl->firstgoto; + + while (i < gl->n) { + if (ktapc_ts_eqstr(gl->arr[i].name, lb->name)) + closegoto(ls, i, lb); + else + i++; + } +} + +/* + * "export" pending gotos to outer level, to check them against + * outer labels; if the block being exited has upvalues, and + * the goto exits the scope of any variable (which can be the + * upvalue), close those variables being exited. + */ +static void movegotosout(ktap_funcstate *fs, ktap_blockcnt *bl) +{ + int i = bl->firstgoto; + ktap_labellist *gl = &fs->ls->dyd->gt; + + /* correct pending gotos to current block and try to close it + with visible labels */ + while (i < gl->n) { + ktap_labeldesc *gt = &gl->arr[i]; + + if (gt->nactvar > bl->nactvar) { + if (bl->upval) + codegen_patchclose(fs, gt->pc, bl->nactvar); + gt->nactvar = bl->nactvar; + } + if (!findlabel(fs->ls, i)) + i++; /* move to next one */ + } +} + +static void enterblock(ktap_funcstate *fs, ktap_blockcnt *bl, u8 isloop) +{ + bl->isloop = isloop; + bl->nactvar = fs->nactvar; + bl->firstlabel = fs->ls->dyd->label.n; + bl->firstgoto = fs->ls->dyd->gt.n; + bl->upval = 0; + bl->previous = fs->bl; + fs->bl = bl; + ktap_assert(fs->freereg == fs->nactvar); +} + + +/* + * create a label named "break" to resolve break statements + */ +static void breaklabel(ktap_lexstate *ls) +{ + ktap_string *n = ktapc_ts_new("break"); + int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); + + findgotos(ls, &ls->dyd->label.arr[l]); +} + +/* + * generates an error for an undefined 'goto'; choose appropriate + * message when label name is a reserved word (which can only be 'break') + */ +static void undefgoto(ktap_lexstate *ls, ktap_labeldesc *gt) +{ + const char *msg = isreserved(gt->name) + ? "<%s> at line %d not inside a loop" + : "no visible label " KTAP_QS " for <goto> at line %d"; + + msg = ktapc_sprintf(msg, getstr(gt->name), gt->line); + semerror(ls, msg); +} + +static void leaveblock(ktap_funcstate *fs) +{ + ktap_blockcnt *bl = fs->bl; + ktap_lexstate *ls = fs->ls; + if (bl->previous && bl->upval) { + /* create a 'jump to here' to close upvalues */ + int j = codegen_jump(fs); + + codegen_patchclose(fs, j, bl->nactvar); + codegen_patchtohere(fs, j); + } + + if (bl->isloop) + breaklabel(ls); /* close pending breaks */ + + fs->bl = bl->previous; + removevars(fs, bl->nactvar); + ktap_assert(bl->nactvar == fs->nactvar); + fs->freereg = fs->nactvar; /* free registers */ + ls->dyd->label.n = bl->firstlabel; /* remove local labels */ + if (bl->previous) /* inner block? */ + movegotosout(fs, bl); /* update pending gotos to outer block */ + else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ + undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ +} + +/* + * adds a new prototype into list of prototypes + */ +static ktap_proto *addprototype(ktap_lexstate *ls) +{ + ktap_proto *clp; + ktap_funcstate *fs = ls->fs; + ktap_proto *f = fs->f; /* prototype of current function */ + + if (fs->np >= f->sizep) { + int oldsize = f->sizep; + ktapc_growvector(f->p, fs->np, f->sizep, ktap_proto *, MAXARG_Bx, "functions"); + while (oldsize < f->sizep) + f->p[oldsize++] = NULL; + } + f->p[fs->np++] = clp = ktapc_newproto(); + return clp; +} + +/* + * codes instruction to create new closure in parent function + */ +static void codeclosure(ktap_lexstate *ls, ktap_expdesc *v) +{ + ktap_funcstate *fs = ls->fs->prev; + init_exp(v, VRELOCABLE, codegen_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); + codegen_exp2nextreg(fs, v); /* fix it at stack top (for GC) */ +} + +static void open_func(ktap_lexstate *ls, ktap_funcstate *fs, ktap_blockcnt *bl) +{ + ktap_proto *f; + + fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + ls->fs = fs; + fs->pc = 0; + fs->lasttarget = 0; + fs->jpc = NO_JUMP; + fs->freereg = 0; + fs->nk = 0; + fs->np = 0; + fs->nups = 0; + fs->nlocvars = 0; + fs->nactvar = 0; + fs->firstlocal = ls->dyd->actvar.n; + fs->bl = NULL; + f = fs->f; + f->source = ls->source; + f->maxstacksize = 2; /* registers 0/1 are always valid */ + fs->h = ktapc_table_new(); + //table_resize(NULL, fs->h, 32, 32); + enterblock(fs, bl, 0); +} + +static void close_func(ktap_lexstate *ls) +{ + ktap_funcstate *fs = ls->fs; + ktap_proto *f = fs->f; + + codegen_ret(fs, 0, 0); /* final return */ + leaveblock(fs); + ktapc_reallocvector(f->code, f->sizecode, fs->pc, ktap_instruction); + f->sizecode = fs->pc; + ktapc_reallocvector(f->lineinfo, f->sizelineinfo, fs->pc, int); + f->sizelineinfo = fs->pc; + ktapc_reallocvector(f->k, f->sizek, fs->nk, ktap_value); + f->sizek = fs->nk; + ktapc_reallocvector(f->p, f->sizep, fs->np, ktap_proto *); + f->sizep = fs->np; + ktapc_reallocvector(f->locvars, f->sizelocvars, fs->nlocvars, ktap_locvar); + f->sizelocvars = fs->nlocvars; + ktapc_reallocvector(f->upvalues, f->sizeupvalues, fs->nups, ktap_upvaldesc); + f->sizeupvalues = fs->nups; + ktap_assert((int)(fs->bl == NULL)); + ls->fs = fs->prev; + /* last token read was anchored in defunct function; must re-anchor it */ + anchor_token(ls); +} + +/*============================================================*/ +/* GRAMMAR RULES */ +/*============================================================*/ + +/* + * check whether current token is in the follow set of a block. + * 'until' closes syntactical blocks, but do not close scope, + * so it handled in separate. + */ +static int block_follow(ktap_lexstate *ls, int withuntil) +{ + switch (ls->t.token) { + case TK_ELSE: case TK_ELSEIF: + case TK_END: case TK_EOS: + return 1; + case TK_UNTIL: + return withuntil; + case '}': + return 1; + default: + return 0; + } +} + +static void statlist(ktap_lexstate *ls) +{ + /* statlist -> { stat [`;'] } */ + while (!block_follow(ls, 1)) { + if (ls->t.token == TK_RETURN) { + statement(ls); + return; /* 'return' must be last statement */ + } + statement(ls); + } +} + +static void fieldsel(ktap_lexstate *ls, ktap_expdesc *v) +{ + /* fieldsel -> ['.' | ':'] NAME */ + ktap_funcstate *fs = ls->fs; + ktap_expdesc key; + + codegen_exp2anyregup(fs, v); + lex_next(ls); /* skip the dot or colon */ + checkname(ls, &key); + codegen_indexed(fs, v, &key); +} + +static void yindex(ktap_lexstate *ls, ktap_expdesc *v) +{ + /* index -> '[' expr ']' */ + lex_next(ls); /* skip the '[' */ + expr(ls, v); + codegen_exp2val(ls->fs, v); + checknext(ls, ']'); +} + +/* + * {====================================================================== + * Rules for Constructors + * ======================================================================= + */ +struct ConsControl { + ktap_expdesc v; /* last list item read */ + ktap_expdesc *t; /* table descriptor */ + int nh; /* total number of `record' elements */ + int na; /* total number of array elements */ + int tostore; /* number of array elements pending to be stored */ +}; + +static void recfield(ktap_lexstate *ls, struct ConsControl *cc) +{ + /* recfield -> (NAME | `['exp1`]') = exp1 */ + ktap_funcstate *fs = ls->fs; + int reg = ls->fs->freereg; + ktap_expdesc key, val; + int rkkey; + + if (ls->t.token == TK_NAME) { + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checkname(ls, &key); + } else /* ls->t.token == '[' */ + yindex(ls, &key); + + cc->nh++; + checknext(ls, '='); + rkkey = codegen_exp2RK(fs, &key); + expr(ls, &val); + codegen_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, codegen_exp2RK(fs, &val)); + fs->freereg = reg; /* free registers */ +} + +static void closelistfield(ktap_funcstate *fs, struct ConsControl *cc) +{ + if (cc->v.k == VVOID) + return; /* there is no list item */ + codegen_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) { + codegen_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ + cc->tostore = 0; /* no more items pending */ + } +} + +static void lastlistfield(ktap_funcstate *fs, struct ConsControl *cc) +{ + if (cc->tostore == 0) + return; + + if (hasmultret(cc->v.k)) { + codegen_setmultret(fs, &cc->v); + codegen_setlist(fs, cc->t->u.info, cc->na, KTAP_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ + } else { + if (cc->v.k != VVOID) + codegen_exp2nextreg(fs, &cc->v); + codegen_setlist(fs, cc->t->u.info, cc->na, cc->tostore); + } +} + +static void listfield(ktap_lexstate *ls, struct ConsControl *cc) +{ + /* listfield -> exp */ + expr(ls, &cc->v); + checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); + cc->na++; + cc->tostore++; +} + +static void field(ktap_lexstate *ls, struct ConsControl *cc) +{ + /* field -> listfield | recfield */ + switch(ls->t.token) { + case TK_NAME: { /* may be 'listfield' or 'recfield' */ + if (lex_lookahead(ls) != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': { + recfield(ls, cc); + break; + } + default: + listfield(ls, cc); + break; + } +} + +static void constructor(ktap_lexstate *ls, ktap_expdesc *t) +{ + /* constructor -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ + ktap_funcstate *fs = ls->fs; + int line = ls->linenumber; + int pc = codegen_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + struct ConsControl cc; + + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VRELOCABLE, pc); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + codegen_exp2nextreg(ls->fs, t); /* fix it at stack top */ + checknext(ls, '{'); + do { + ktap_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') + break; + closelistfield(fs, &cc); + field(ls, &cc); + } while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + SETARG_B(fs->f->code[pc], ktapc_int2fb(cc.na)); /* set initial array size */ + SETARG_C(fs->f->code[pc], ktapc_int2fb(cc.nh)); /* set initial table size */ +} + +/* }====================================================================== */ + +static void parlist(ktap_lexstate *ls) +{ + /* parlist -> [ param { `,' param } ] */ + ktap_funcstate *fs = ls->fs; + ktap_proto *f = fs->f; + int nparams = 0; + f->is_vararg = 0; + + if (ls->t.token != ')') { /* is `parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_NAME: { /* param -> NAME */ + new_localvar(ls, str_checkname(ls)); + nparams++; + break; + } + case TK_DOTS: { /* param -> `...' */ + lex_next(ls); + f->is_vararg = 1; + break; + } + default: + lex_syntaxerror(ls, "<name> or " KTAP_QL("...") " expected"); + } + } while (!f->is_vararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = (u8)(fs->nactvar); + codegen_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ +} + +static void body(ktap_lexstate *ls, ktap_expdesc *e, int ismethod, int line) +{ + /* body -> `(' parlist `)' block END */ + ktap_funcstate new_fs; + ktap_blockcnt bl; + + new_fs.f = addprototype(ls); + new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); + checknext(ls, '('); + if (ismethod) { + new_localvarliteral(ls, "self"); /* create 'self' parameter */ + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + checknext(ls, '{'); + statlist(ls); + new_fs.f->lastlinedefined = ls->linenumber; + checknext(ls, '}'); + //check_match(ls, TK_END, TK_FUNCTION, line); + codeclosure(ls, e); + close_func(ls); +} + +static void func_body_no_args(ktap_lexstate *ls, ktap_expdesc *e, int line) +{ + /* body -> `(' parlist `)' block END */ + ktap_funcstate new_fs; + ktap_blockcnt bl; + + new_fs.f = addprototype(ls); + new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); + checknext(ls, '{'); + statlist(ls); + new_fs.f->lastlinedefined = ls->linenumber; + checknext(ls, '}'); + //check_match(ls, TK_END, TK_FUNCTION, line); + codeclosure(ls, e); + close_func(ls); +} + +static int explist(ktap_lexstate *ls, ktap_expdesc *v) +{ + /* explist -> expr { `,' expr } */ + int n = 1; /* at least one expression */ + + expr(ls, v); + while (testnext(ls, ',')) { + codegen_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; +} + +static void funcargs(ktap_lexstate *ls, ktap_expdesc *f, int line) +{ + ktap_funcstate *fs = ls->fs; + ktap_expdesc args; + int base, nparams; + + switch (ls->t.token) { + case '(': { /* funcargs -> `(' [ explist ] `)' */ + lex_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist(ls, &args); + codegen_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: { /* funcargs -> STRING */ + codestring(ls, &args, ls->t.seminfo.ts); + lex_next(ls); /* must use `seminfo' before `next' */ + break; + } + default: { + lex_syntaxerror(ls, "function arguments expected"); + } + } + ktap_assert(f->k == VNONRELOC); + base = f->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = KTAP_MULTRET; /* open call */ + else { + if (args.k != VVOID) + codegen_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(f, VCALL, codegen_codeABC(fs, OP_CALL, base, nparams+1, 2)); + codegen_fixline(fs, line); + fs->freereg = base+1; /* call remove function and arguments and leaves + (unless changed) one result */ +} + +/* + * {====================================================================== + * Expression parsing + * ======================================================================= + */ +static void primaryexp(ktap_lexstate *ls, ktap_expdesc *v) +{ + /* primaryexp -> NAME | '(' expr ')' */ + switch (ls->t.token) { + case '(': { + int line = ls->linenumber; + + lex_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + codegen_dischargevars(ls->fs, v); + return; + } + case TK_NAME: + singlevar(ls, v); + return; + default: + lex_syntaxerror(ls, "unexpected symbol"); + } +} + +static void suffixedexp(ktap_lexstate *ls, ktap_expdesc *v) +{ + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ + ktap_funcstate *fs = ls->fs; + int line = ls->linenumber; + + primaryexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* fieldsel */ + fieldsel(ls, v); + break; + } + case '[': { /* `[' exp1 `]' */ + ktap_expdesc key; + codegen_exp2anyregup(fs, v); + yindex(ls, &key); + codegen_indexed(fs, v, &key); + break; + } + case ':': { /* `:' NAME funcargs */ + ktap_expdesc key; + lex_next(ls); + checkname(ls, &key); + codegen_self(fs, v, &key); + funcargs(ls, v, line); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + codegen_exp2nextreg(fs, v); + funcargs(ls, v, line); + break; + } + default: + return; + } + } +} + +static void simpleexp(ktap_lexstate *ls, ktap_expdesc *v) +{ + /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | + constructor | FUNCTION body | suffixedexp */ + switch (ls->t.token) { + case TK_NUMBER: { + init_exp(v, VKNUM, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_STRING: { + codestring(ls, v, ls->t.seminfo.ts); + break; + } + case TK_NIL: { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: { /* vararg */ + ktap_funcstate *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use " KTAP_QL("...") " outside a vararg function"); + init_exp(v, VVARARG, codegen_codeABC(fs, OP_VARARG, 0, 1, 0)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: { + lex_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + case TK_ARGEVENT: + init_exp(v, VEVENT, 0); + break; + + case TK_ARGNAME: + init_exp(v, VEVENTNAME, 0); + break; + case TK_ARG1: + case TK_ARG2: + case TK_ARG3: + case TK_ARG4: + case TK_ARG5: + case TK_ARG6: + case TK_ARG7: + case TK_ARG8: + case TK_ARG9: + init_exp(v, VEVENTARG, ls->t.token - TK_ARG1 + 1); + break; + default: { + suffixedexp(ls, v); + return; + } + } + lex_next(ls); +} + +static UnOpr getunopr(int op) +{ + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } +} + +static BinOpr getbinopr(int op) +{ + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '/': return OPR_DIV; + case '%': return OPR_MOD; + case '^': return OPR_POW; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; + } +} + +static const struct { + u8 left; /* left priority for each binary operator */ + u8 right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `*' `/' `%' */ + {10, 9}, {5, 4}, /* ^, .. (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* !=, >, >= */ + {2, 2}, {1, 1} /* and, or */ +}; + +#define UNARY_PRIORITY 8 /* priority for unary operators */ + +#define leavelevel(ls) (ls->nCcalls--) + +/* + * subexpr -> (simpleexp | unop subexpr) { binop subexpr } + * where `binop' is any binary operator with a priority higher than `limit' + */ +static BinOpr subexpr(ktap_lexstate *ls, ktap_expdesc *v, int limit) +{ + BinOpr op; + UnOpr uop; + + enterlevel(ls); + uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { + int line = ls->linenumber; + + lex_next(ls); + subexpr(ls, v, UNARY_PRIORITY); + codegen_prefix(ls->fs, uop, v, line); + } else + simpleexp(ls, v); + + /* expand while operators have priorities higher than `limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + ktap_expdesc v2; + BinOpr nextop; + int line = ls->linenumber; + + lex_next(ls); + codegen_infix(ls->fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + codegen_posfix(ls->fs, op, v, &v2, line); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ +} + +static void expr(ktap_lexstate *ls, ktap_expdesc *v) +{ + subexpr(ls, v, 0); +} + +/* }==================================================================== */ + +/* + * {====================================================================== + * Rules for Statements + * ======================================================================= + */ +static void block(ktap_lexstate *ls) +{ + /* block -> statlist */ + ktap_funcstate *fs = ls->fs; + ktap_blockcnt bl; + + enterblock(fs, &bl, 0); + statlist(ls); + leaveblock(fs); +} + +/* + * structure to chain all variables in the left-hand side of an + * assignment + */ +struct LHS_assign { + struct LHS_assign *prev; + ktap_expdesc v; /* variable (global, local, upvalue, or indexed) */ +}; + +/* + * check whether, in an assignment to an upvalue/local variable, the + * upvalue/local variable is begin used in a previous assignment to a + * table. If so, save original upvalue/local value in a safe place and + * use this safe copy in the previous assignment. + */ +static void check_conflict(ktap_lexstate *ls, struct LHS_assign *lh, ktap_expdesc *v) +{ + ktap_funcstate *fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + + for (; lh; lh = lh->prev) { /* check all previous assignments */ + if (lh->v.k == VINDEXED) { /* assigning to a table? */ + /* table is the upvalue/local being assigned now? */ + if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { + conflict = 1; + lh->v.u.ind.vt = VLOCAL; + lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ + } + /* index is the local being assigned? (index cannot be upvalue) */ + if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { + conflict = 1; + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ + } + } + } + if (conflict) { + /* copy upvalue/local value to a temporary (in position 'extra') */ + OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + codegen_codeABC(fs, op, extra, v->u.info, 0); + codegen_reserveregs(fs, 1); + } +} + +static void assignment(ktap_lexstate *ls, struct LHS_assign *lh, int nvars) +{ + ktap_expdesc e; + + check_condition(ls, vkisvar(lh->v.k), "syntax error"); + if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ + struct LHS_assign nv; + + nv.prev = lh; + suffixedexp(ls, &nv.v); + if (nv.v.k != VINDEXED) + check_conflict(ls, lh, &nv.v); + checklimit(ls->fs, nvars + ls->nCcalls, KTAP_MAXCCALLS, + "C levels"); + assignment(ls, &nv, nvars+1); + } else if (testnext(ls, '=')) { /* assignment -> '=' explist */ + int nexps; + + nexps = explist(ls, &e); + if (nexps != nvars) { + adjust_assign(ls, nvars, nexps, &e); + /* remove extra values */ + if (nexps > nvars) + ls->fs->freereg -= nexps - nvars; + } else { + /* close last expression */ + codegen_setoneret(ls->fs, &e); + codegen_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } else if (testnext(ls, TK_INCR)) { /* assignment -> '+=' explist */ + int nexps; + + nexps = explist(ls, &e); + if (nexps != nvars) { + lex_syntaxerror(ls, "don't allow multi-assign for +="); + } else { + /* close last expression */ + codegen_setoneret(ls->fs, &e); + codegen_storeincr(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + codegen_storevar(ls->fs, &lh->v, &e); +} + +static int cond(ktap_lexstate *ls) +{ + /* cond -> exp */ + ktap_expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) + v.k = VFALSE; /* `falses' are all equal here */ + codegen_goiftrue(ls->fs, &v); + return v.f; +} + +static void gotostat(ktap_lexstate *ls, int pc) +{ + int line = ls->linenumber; + ktap_string *label; + int g; + + if (testnext(ls, TK_GOTO)) + label = str_checkname(ls); + else { + lex_next(ls); /* skip break */ + label = ktapc_ts_new("break"); + } + g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); + findlabel(ls, g); /* close it if label already defined */ +} + +/* check for repeated labels on the same block */ +static void checkrepeated(ktap_funcstate *fs, ktap_labellist *ll, ktap_string *label) +{ + int i; + for (i = fs->bl->firstlabel; i < ll->n; i++) { + if (ktapc_ts_eqstr(label, ll->arr[i].name)) { + const char *msg = ktapc_sprintf( + "label " KTAP_QS " already defined on line %d", + getstr(label), ll->arr[i].line); + semerror(fs->ls, msg); + } + } +} + +/* skip no-op statements */ +static void skipnoopstat(ktap_lexstate *ls) +{ + while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) + statement(ls); +} + +static void labelstat (ktap_lexstate *ls, ktap_string *label, int line) +{ + /* label -> '::' NAME '::' */ + ktap_funcstate *fs = ls->fs; + ktap_labellist *ll = &ls->dyd->label; + int l; /* index of new label being created */ + + checkrepeated(fs, ll, label); /* check for repeated labels */ + checknext(ls, TK_DBCOLON); /* skip double colon */ + /* create new entry for this label */ + l = newlabelentry(ls, ll, label, line, fs->pc); + skipnoopstat(ls); /* skip other no-op statements */ + if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ + /* assume that locals are already out of scope */ + ll->arr[l].nactvar = fs->bl->nactvar; + } + findgotos(ls, &ll->arr[l]); +} + +static void whilestat(ktap_lexstate *ls, int line) +{ + /* whilestat -> WHILE cond DO block END */ + ktap_funcstate *fs = ls->fs; + int whileinit; + int condexit; + ktap_blockcnt bl; + + lex_next(ls); /* skip WHILE */ + whileinit = codegen_getlabel(fs); + checknext(ls, '('); + condexit = cond(ls); + checknext(ls, ')'); + + enterblock(fs, &bl, 1); + //checknext(ls, TK_DO); + checknext(ls, '{'); + block(ls); + codegen_jumpto(fs, whileinit); + checknext(ls, '}'); + //check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + codegen_patchtohere(fs, condexit); /* false conditions finish the loop */ +} + +static void repeatstat(ktap_lexstate *ls, int line) +{ + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + ktap_funcstate *fs = ls->fs; + int repeat_init = codegen_getlabel(fs); + ktap_blockcnt bl1, bl2; + + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + lex_next(ls); /* skip REPEAT */ + statlist(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + if (bl2.upval) /* upvalues? */ + codegen_patchclose(fs, condexit, bl2.nactvar); + leaveblock(fs); /* finish scope */ + codegen_patchlist(fs, condexit, repeat_init); /* close the loop */ + leaveblock(fs); /* finish loop */ +} + +static int exp1(ktap_lexstate *ls) +{ + ktap_expdesc e; + int reg; + + expr(ls, &e); + codegen_exp2nextreg(ls->fs, &e); + ktap_assert(e.k == VNONRELOC); + reg = e.u.info; + return reg; +} + +static void forbody(ktap_lexstate *ls, int base, int line, int nvars, int isnum) +{ + /* forbody -> DO block */ + ktap_blockcnt bl; + ktap_funcstate *fs = ls->fs; + int prep, endfor; + + checknext(ls, ')'); + + adjustlocalvars(ls, 3); /* control variables */ + //checknext(ls, TK_DO); + checknext(ls, '{'); + prep = isnum ? codegen_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : codegen_jump(fs); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + codegen_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + codegen_patchtohere(fs, prep); + if (isnum) /* numeric for? */ + endfor = codegen_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); + else { /* generic for */ + codegen_codeABC(fs, OP_TFORCALL, base, 0, nvars); + codegen_fixline(fs, line); + endfor = codegen_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); + } + codegen_patchlist(fs, endfor, prep + 1); + codegen_fixline(fs, line); +} + +static void fornum(ktap_lexstate *ls, ktap_string *varname, int line) +{ + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + ktap_funcstate *fs = ls->fs; + int base = fs->freereg; + + new_localvarliteral(ls, "(for index)"); + new_localvarliteral(ls, "(for limit)"); + new_localvarliteral(ls, "(for step)"); + new_localvar(ls, varname); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + codegen_codek(fs, fs->freereg, codegen_numberK(fs, 1)); + codegen_reserveregs(fs, 1); + } + forbody(ls, base, line, 1, 1); +} + +static void forlist(ktap_lexstate *ls, ktap_string *indexname) +{ + /* forlist -> NAME {,NAME} IN explist forbody */ + ktap_funcstate *fs = ls->fs; + ktap_expdesc e; + int nvars = 4; /* gen, state, control, plus at least one declared var */ + int line; + int base = fs->freereg; + + /* create control variables */ + new_localvarliteral(ls, "(for generator)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for control)"); + /* create declared variables */ + new_localvar(ls, indexname); + while (testnext(ls, ',')) { + new_localvar(ls, str_checkname(ls)); + nvars++; + } + checknext(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, 3, explist(ls, &e), &e); + codegen_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 3, 0); +} + +static void forstat(ktap_lexstate *ls, int line) +{ + /* forstat -> FOR (fornum | forlist) END */ + ktap_funcstate *fs = ls->fs; + ktap_string *varname; + ktap_blockcnt bl; + + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + lex_next(ls); /* skip `for' */ + + checknext(ls, '('); + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': + fornum(ls, varname, line); + break; + case ',': case TK_IN: + forlist(ls, varname); + break; + default: + lex_syntaxerror(ls, KTAP_QL("=") " or " KTAP_QL("in") " expected"); + } + //check_match(ls, TK_END, TK_FOR, line); + checknext(ls, '}'); + leaveblock(fs); /* loop scope (`break' jumps to this point) */ +} + +static void test_then_block(ktap_lexstate *ls, int *escapelist) +{ + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + ktap_blockcnt bl; + ktap_funcstate *fs = ls->fs; + ktap_expdesc v; + int jf; /* instruction to skip 'then' code (if condition is false) */ + + lex_next(ls); /* skip IF or ELSEIF */ + checknext(ls, '('); + expr(ls, &v); /* read condition */ + checknext(ls, ')'); + //checknext(ls, TK_THEN); + checknext(ls, '{'); + if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { + codegen_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ + enterblock(fs, &bl, 0); /* must enter block before 'goto' */ + gotostat(ls, v.t); /* handle goto/break */ + skipnoopstat(ls); /* skip other no-op statements */ + if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ + leaveblock(fs); + checknext(ls, '}'); + return; /* and that is it */ + } else /* must skip over 'then' part if condition is false */ + jf = codegen_jump(fs); + } else { /* regular case (not goto/break) */ + codegen_goiftrue(ls->fs, &v); /* skip over block if condition is false */ + enterblock(fs, &bl, 0); + jf = v.f; + } + statlist(ls); /* `then' part */ + checknext(ls, '}'); + leaveblock(fs); + if (ls->t.token == TK_ELSE || ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ + codegen_concat(fs, escapelist, codegen_jump(fs)); /* must jump over it */ + codegen_patchtohere(fs, jf); +} + +static void ifstat(ktap_lexstate *ls, int line) +{ + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + ktap_funcstate *fs = ls->fs; + int escapelist = NO_JUMP; /* exit list for finished parts */ + + test_then_block(ls, &escapelist); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) + test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ + if (testnext(ls, TK_ELSE)) { + checknext(ls, '{'); + block(ls); /* `else' part */ + checknext(ls, '}'); + } + //check_match(ls, TK_END, TK_IF, line); + codegen_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ +} + +static void localfunc(ktap_lexstate *ls) +{ + ktap_expdesc b; + ktap_funcstate *fs = ls->fs; + + new_localvar(ls, str_checkname(ls)); /* new local variable */ + adjustlocalvars(ls, 1); /* enter its scope */ + body(ls, &b, 0, ls->linenumber); /* function created in next register */ + /* debug information will only see the variable after this point! */ + getlocvar(fs, b.u.info)->startpc = fs->pc; +} + +static void localstat(ktap_lexstate *ls) +{ + /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */ + int nvars = 0; + int nexps; + ktap_expdesc e; + + do { + new_localvar(ls, str_checkname(ls)); + nvars++; + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist(ls, &e); + else { + e.k = VVOID; + nexps = 0; + } + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); +} + +static int funcname(ktap_lexstate *ls, ktap_expdesc *v) +{ + /* funcname -> NAME {fieldsel} [`:' NAME] */ + int ismethod = 0; + + singlevar(ls, v); + while (ls->t.token == '.') + fieldsel(ls, v); + if (ls->t.token == ':') { + ismethod = 1; + fieldsel(ls, v); + } + return ismethod; +} + +static void funcstat(ktap_lexstate *ls, int line) +{ + /* funcstat -> FUNCTION funcname body */ + int ismethod; + ktap_expdesc v, b; + + lex_next(ls); /* skip FUNCTION */ + ismethod = funcname(ls, &v); + body(ls, &b, ismethod, line); + codegen_storevar(ls->fs, &v, &b); + codegen_fixline(ls->fs, line); /* definition `happens' in the first line */ +} + +static void exprstat(ktap_lexstate *ls) +{ + /* stat -> func | assignment */ + ktap_funcstate *fs = ls->fs; + struct LHS_assign v; + + suffixedexp(ls, &v.v); + /* stat -> assignment ? */ + if (ls->t.token == '=' || ls->t.token == ',' || + ls->t.token == TK_INCR) { + v.prev = NULL; + assignment(ls, &v, 1); + } else { /* stat -> func */ + check_condition(ls, v.v.k == VCALL, "syntax error"); + SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ + } +} + +static void retstat(ktap_lexstate *ls) +{ + /* stat -> RETURN [explist] [';'] */ + ktap_funcstate *fs = ls->fs; + ktap_expdesc e; + int first, nret; /* registers with returned values */ + + if (block_follow(ls, 1) || ls->t.token == ';') + first = nret = 0; /* return no values */ + else { + nret = explist(ls, &e); /* optional return values */ + if (hasmultret(e.k)) { + codegen_setmultret(fs, &e); + if (e.k == VCALL && nret == 1) { /* tail call? */ + SET_OPCODE(getcode(fs,&e), OP_TAILCALL); + ktap_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); + } + first = fs->nactvar; + nret = KTAP_MULTRET; /* return all values */ + } else { + if (nret == 1) /* only one single value? */ + first = codegen_exp2anyreg(fs, &e); + else { + codegen_exp2nextreg(fs, &e); /* values must go to the `stack' */ + first = fs->nactvar; /* return all `active' values */ + ktap_assert(nret == fs->freereg - first); + } + } + } + codegen_ret(fs, first, nret); + testnext(ls, ';'); /* skip optional semicolon */ +} + +static void tracestat(ktap_lexstate *ls) +{ + ktap_expdesc v0, key, args; + ktap_expdesc *v = &v0; + ktap_string *kdebug_str = ktapc_ts_new("kdebug"); + ktap_string *probe_str = ktapc_ts_new("probe_by_id"); + ktap_string *probe_end_str = ktapc_ts_new("probe_end"); + ktap_funcstate *fs = ls->fs; + int token = ls->t.token; + int line = ls->linenumber; + int base, nparams; + + if (token == TK_TRACE) + lex_read_string_until(ls, '{'); + else + lex_next(ls); /* skip "trace_end" keyword */ + + /* kdebug */ + singlevaraux(fs, ls->envn, v, 1); /* get environment variable */ + codestring(ls, &key, kdebug_str); /* key is variable name */ + codegen_indexed(fs, v, &key); /* env[varname] */ + + /* fieldsel: kdebug.probe */ + codegen_exp2anyregup(fs, v); + if (token == TK_TRACE) + codestring(ls, &key, probe_str); + else if (token == TK_TRACE_END) + codestring(ls, &key, probe_end_str); + codegen_indexed(fs, v, &key); + + /* funcargs*/ + codegen_exp2nextreg(fs, v); + + if (token == TK_TRACE) { + /* argument: EVENTDEF string */ + check(ls, TK_STRING); + enterlevel(ls); + ktap_string *ts = ktapc_parse_eventdef(ls->t.seminfo.ts); + check_condition(ls, ts != NULL, "Cannot parse eventdef"); + codestring(ls, &args, ts); + lex_next(ls); /* skip EVENTDEF string */ + leavelevel(ls); + + codegen_exp2nextreg(fs, &args); /* for next argument */ + } + + /* argument: callback function */ + enterlevel(ls); + func_body_no_args(ls, &args, ls->linenumber); + leavelevel(ls); + + codegen_setmultret(fs, &args); + + base = v->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = KTAP_MULTRET; /* open call */ + else { + codegen_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(v, VCALL, codegen_codeABC(fs, OP_CALL, base, nparams+1, 2)); + codegen_fixline(fs, line); + fs->freereg = base+1; + + check_condition(ls, v->k == VCALL, "syntax error"); + SETARG_C(getcode(fs, v), 1); /* call statement uses no results */ +} + +static void timerstat(ktap_lexstate *ls) +{ + ktap_expdesc v0, key, args; + ktap_expdesc *v = &v0; + ktap_funcstate *fs = ls->fs; + ktap_string *token_str = ls->t.seminfo.ts; + ktap_string *interval_str; + int line = ls->linenumber; + int base, nparams; + + lex_next(ls); /* skip profile/tick keyword */ + check(ls, '-'); + + lex_read_string_until(ls, '{'); + interval_str = ls->t.seminfo.ts; + + //printf("timerstat str: %s\n", getstr(interval_str)); + //exit(0); + + /* timer */ + singlevaraux(fs, ls->envn, v, 1); /* get environment variable */ + codestring(ls, &key, ktapc_ts_new("timer")); /* key is variable name */ + codegen_indexed(fs, v, &key); /* env[varname] */ + + /* fieldsel: timer.profile, timer.tick */ + codegen_exp2anyregup(fs, v); + codestring(ls, &key, token_str); + codegen_indexed(fs, v, &key); + + /* funcargs*/ + codegen_exp2nextreg(fs, v); + + /* argument: interval string */ + check(ls, TK_STRING); + enterlevel(ls); + codestring(ls, &args, interval_str); + lex_next(ls); /* skip interval string */ + leavelevel(ls); + + codegen_exp2nextreg(fs, &args); /* for next argument */ + + /* argument: callback function */ + enterlevel(ls); + func_body_no_args(ls, &args, ls->linenumber); + leavelevel(ls); + + codegen_setmultret(fs, &args); + + base = v->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = KTAP_MULTRET; /* open call */ + else { + codegen_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(v, VCALL, codegen_codeABC(fs, OP_CALL, base, nparams+1, 2)); + codegen_fixline(fs, line); + fs->freereg = base+1; + + check_condition(ls, v->k == VCALL, "syntax error"); + SETARG_C(getcode(fs, v), 1); /* call statement uses no results */ +} + +static void statement(ktap_lexstate *ls) +{ + int line = ls->linenumber; /* may be needed for error messages */ + + enterlevel(ls); + switch (ls->t.token) { + case ';': { /* stat -> ';' (empty statement) */ + lex_next(ls); /* skip ';' */ + break; + } + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + break; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + break; + } + case TK_DO: { /* stat -> DO block END */ + lex_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + break; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + break; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + break; + } + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + break; + } + case TK_LOCAL: { /* stat -> localstat */ + lex_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + break; + } + case TK_DBCOLON: { /* stat -> label */ + lex_next(ls); /* skip double colon */ + labelstat(ls, str_checkname(ls), line); + break; + } + case TK_RETURN: { /* stat -> retstat */ + lex_next(ls); /* skip RETURN */ + retstat(ls); + break; + } + case TK_BREAK: /* stat -> breakstat */ + case TK_GOTO: { /* stat -> 'goto' NAME */ + gotostat(ls, codegen_jump(ls->fs)); + break; + } + + case TK_TRACE: + case TK_TRACE_END: + tracestat(ls); + break; + case TK_PROFILE: + case TK_TICK: + timerstat(ls); + break; + default: { /* stat -> func | assignment */ + exprstat(ls); + break; + } + } + //ktap_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + // ls->fs->freereg >= ls->fs->nactvar); + ls->fs->freereg = ls->fs->nactvar; /* free registers */ + leavelevel(ls); +} +/* }====================================================================== */ + +/* + * compiles the main function, which is a regular vararg function with an upvalue + */ +static void mainfunc(ktap_lexstate *ls, ktap_funcstate *fs) +{ + ktap_blockcnt bl; + ktap_expdesc v; + + open_func(ls, fs, &bl); + fs->f->is_vararg = 1; /* main function is always vararg */ + init_exp(&v, VLOCAL, 0); /* create and... */ + newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ + lex_next(ls); /* read first token */ + statlist(ls); /* parse main body */ + check(ls, TK_EOS); + close_func(ls); +} + +ktap_closure *ktapc_parser(char *ptr, const char *name) +{ + ktap_lexstate lexstate; + ktap_funcstate funcstate; + ktap_dyndata dyd; + ktap_mbuffer buff; + int firstchar = *ptr++; + ktap_closure *cl = ktapc_newlclosure(1); /* create main closure */ + + memset(&lexstate, 0, sizeof(ktap_lexstate)); + memset(&funcstate, 0, sizeof(ktap_funcstate)); + funcstate.f = cl->l.p = ktapc_newproto(); + funcstate.f->source = ktapc_ts_new(name); /* create and anchor ktap_string */ + + lex_init(); + + mbuff_init(&buff); + memset(&dyd, 0, sizeof(ktap_dyndata)); + lexstate.buff = &buff; + lexstate.dyd = &dyd; + lex_setinput(&lexstate, ptr, funcstate.f->source, firstchar); + + mainfunc(&lexstate, &funcstate); + + ktap_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); + + /* all scopes should be correctly finished */ + ktap_assert(dyd.actvar.n == 0 && dyd.gt.n == 0 && dyd.label.n == 0); + return cl; +} + diff --git a/drivers/staging/ktap/userspace/util.c b/drivers/staging/ktap/userspace/util.c new file mode 100644 index 000000000000..8124de995be7 --- /dev/null +++ b/drivers/staging/ktap/userspace/util.c @@ -0,0 +1,346 @@ +/* + * util.c + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. + * + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. + * - The part of code in this file is copied from lua initially. + * - lua's MIT license is compatible with GPL. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap 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, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "../include/ktap_types.h" +#include "ktapc.h" + +/* + * converts an integer to a "floating point byte", represented as + * (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if + * eeeee != 0 and (xxx) otherwise. + */ +int ktapc_int2fb(unsigned int x) +{ + int e = 0; /* exponent */ + + if (x < 8) + return x; + while (x >= 0x10) { + x = (x+1) >> 1; + e++; + } + return ((e+1) << 3) | ((int)x - 8); +} + +/* converts back */ +int ktapc_fb2int(int x) +{ + int e = (x >> 3) & 0x1f; + + if (e == 0) + return x; + else + return ((x & 7) + 8) << (e - 1); +} + +int ktapc_ceillog2(unsigned int x) +{ + static const u8 log_2[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + int l = 0; + + x--; + while (x >= 256) { + l += 8; + x >>= 8; + } + return l + log_2[x]; +} + +ktap_number ktapc_arith(int op, ktap_number v1, ktap_number v2) +{ + switch (op) { + case KTAP_OPADD: return NUMADD(v1, v2); + case KTAP_OPSUB: return NUMSUB(v1, v2); + case KTAP_OPMUL: return NUMMUL(v1, v2); + case KTAP_OPDIV: return NUMDIV(v1, v2); + case KTAP_OPMOD: return NUMMOD(v1, v2); + //case KTAP_OPPOW: return NUMPOW(v1, v2); + case KTAP_OPUNM: return NUMUNM(v1); + default: ktap_assert(0); return 0; + } +} + +int ktapc_hexavalue(int c) +{ + if (isdigit(c)) + return c - '0'; + else + return tolower(c) - 'a' + 10; +} + +static int isneg(const char **s) +{ + if (**s == '-') { + (*s)++; + return 1; + } else if (**s == '+') + (*s)++; + + return 0; +} + +static ktap_number readhexa(const char **s, ktap_number r, int *count) +{ + for (; isxdigit((unsigned char)(**s)); (*s)++) { /* read integer part */ + r = (r * 16.0) + (ktap_number)(ktapc_hexavalue((unsigned char)(**s))); + (*count)++; + } + + return r; +} + +/* + * convert an hexadecimal numeric string to a number, following + * C99 specification for 'strtod' + */ +static ktap_number strx2number(const char *s, char **endptr) +{ + ktap_number r = 0.0; + int e = 0, i = 0; + int neg = 0; /* 1 if number is negative */ + + *endptr = (char *)s; /* nothing is valid yet */ + while (isspace((unsigned char)(*s))) + s++; /* skip initial spaces */ + + neg = isneg(&s); /* check signal */ + if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ + return 0.0; /* invalid format (no '0x') */ + + s += 2; /* skip '0x' */ + r = readhexa(&s, r, &i); /* read integer part */ + if (*s == '.') { + s++; /* skip dot */ + r = readhexa(&s, r, &e); /* read fractional part */ + } + + if (i == 0 && e == 0) + return 0.0; /* invalid format (no digit) */ + e *= -4; /* each fractional digit divides value by 2^-4 */ + *endptr = (char *)s; /* valid up to here */ + + if (*s == 'p' || *s == 'P') { /* exponent part? */ + int exp1 = 0; + int neg1; + + s++; /* skip 'p' */ + neg1 = isneg(&s); /* signal */ + if (!isdigit((unsigned char)(*s))) + goto ret; /* must have at least one digit */ + while (isdigit((unsigned char)(*s))) /* read exponent */ + exp1 = exp1 * 10 + *(s++) - '0'; + if (neg1) exp1 = -exp1; + e += exp1; + } + + *endptr = (char *)s; /* valid up to here */ + ret: + if (neg) + r = -r; + + return ldexp(r, e); +} + +int ktapc_str2d(const char *s, size_t len, ktap_number *result) +{ + char *endptr; + + if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ + return 0; + else if (strpbrk(s, "xX")) /* hexa? */ + *result = strx2number(s, &endptr); + else + *result = strtod(s, &endptr); + + if (endptr == s) + return 0; /* nothing recognized */ + while (isspace((unsigned char)(*endptr))) + endptr++; + return (endptr == s + len); /* OK if no trailing characters */ +} + +/* number of chars of a literal string without the ending \0 */ +#define LL(x) (sizeof(x)/sizeof(char) - 1) + +#define RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) + +void ktapc_chunkid(char *out, const char *source, size_t bufflen) +{ + size_t l = strlen(source); + + if (*source == '=') { /* 'literal' source */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l * sizeof(char)); + else { /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } + } else if (*source == '@') { /* file name */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l * sizeof(char)); + else { /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); + } + } else { /* string; format as [string "source"] */ + const char *nl = strchr(source, '\n'); /* find first new line (if any) */ + addstr(out, PRE, LL(PRE)); /* add prefix */ + bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ + if (l < bufflen && nl == NULL) { /* small one-line source? */ + addstr(out, source, l); /* keep it */ + } else { + if (nl != NULL) + l = nl - source; /* stop at first newline */ + if (l > bufflen) + l = bufflen; + addstr(out, source, l); + addstr(out, RETS, LL(RETS)); + } + memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); + } +} + + +/* + * strglobmatch is copyed from perf(linux/tools/perf/util/string.c) + */ + +/* Character class matching */ +static bool __match_charclass(const char *pat, char c, const char **npat) +{ + bool complement = false, ret = true; + + if (*pat == '!') { + complement = true; + pat++; + } + if (*pat++ == c) /* First character is special */ + goto end; + + while (*pat && *pat != ']') { /* Matching */ + if (*pat == '-' && *(pat + 1) != ']') { /* Range */ + if (*(pat - 1) <= c && c <= *(pat + 1)) + goto end; + if (*(pat - 1) > *(pat + 1)) + goto error; + pat += 2; + } else if (*pat++ == c) + goto end; + } + if (!*pat) + goto error; + ret = false; + +end: + while (*pat && *pat != ']') /* Searching closing */ + pat++; + if (!*pat) + goto error; + *npat = pat + 1; + return complement ? !ret : ret; + +error: + return false; +} + +/* Glob/lazy pattern matching */ +static bool __match_glob(const char *str, const char *pat, bool ignore_space) +{ + while (*str && *pat && *pat != '*') { + if (ignore_space) { + /* Ignore spaces for lazy matching */ + if (isspace(*str)) { + str++; + continue; + } + if (isspace(*pat)) { + pat++; + continue; + } + } + if (*pat == '?') { /* Matches any single character */ + str++; + pat++; + continue; + } else if (*pat == '[') /* Character classes/Ranges */ + if (__match_charclass(pat + 1, *str, &pat)) { + str++; + continue; + } else + return false; + else if (*pat == '\\') /* Escaped char match as normal char */ + pat++; + if (*str++ != *pat++) + return false; + } + /* Check wild card */ + if (*pat == '*') { + while (*pat == '*') + pat++; + if (!*pat) /* Tail wild card matches all */ + return true; + while (*str) + if (__match_glob(str++, pat, ignore_space)) + return true; + } + return !*str && !*pat; +} + +/** + * strglobmatch - glob expression pattern matching + * @str: the target string to match + * @pat: the pattern string to match + * + * This returns true if the @str matches @pat. @pat can includes wildcards + * ('*','?') and character classes ([CHARS], complementation and ranges are + * also supported). Also, this supports escape character ('\') to use special + * characters as normal character. + * + * Note: if @pat syntax is broken, this always returns false. + */ +bool strglobmatch(const char *str, const char *pat) +{ + return __match_glob(str, pat, false); +} + diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c index e3f9a53dbd96..52da4d9d2164 100644 --- a/drivers/staging/line6/midi.c +++ b/drivers/staging/line6/midi.c @@ -205,7 +205,7 @@ static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, if (up) line6->line6midi->substream_receive = substream; else - line6->line6midi->substream_receive = 0; + line6->line6midi->substream_receive = NULL; } static struct snd_rawmidi_ops line6_midi_output_ops = { diff --git a/drivers/staging/lustre/lnet/lnet/lo.c b/drivers/staging/lustre/lnet/lnet/lo.c index 670dae34107c..efc798e01934 100644 --- a/drivers/staging/lustre/lnet/lnet/lo.c +++ b/drivers/staging/lustre/lnet/lnet/lo.c @@ -36,16 +36,16 @@ #include <linux/lnet/lib-lnet.h> int -lolnd_send (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) +lolnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) { - LASSERT (!lntmsg->msg_routing); - LASSERT (!lntmsg->msg_target_is_router); + LASSERT(!lntmsg->msg_routing); + LASSERT(!lntmsg->msg_target_is_router); return lnet_parse(ni, &lntmsg->msg_hdr, ni->ni_nid, lntmsg, 0); } int -lolnd_recv (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, +lolnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed, unsigned int niov, struct iovec *iov, lnet_kiov_t *kiov, unsigned int offset, unsigned int mlen, unsigned int rlen) @@ -89,20 +89,20 @@ static int lolnd_instanced; void lolnd_shutdown(lnet_ni_t *ni) { - CDEBUG (D_NET, "shutdown\n"); - LASSERT (lolnd_instanced); + CDEBUG(D_NET, "shutdown\n"); + LASSERT(lolnd_instanced); lolnd_instanced = 0; } int -lolnd_startup (lnet_ni_t *ni) +lolnd_startup(lnet_ni_t *ni) { - LASSERT (ni->ni_lnd == &the_lolnd); - LASSERT (!lolnd_instanced); + LASSERT(ni->ni_lnd == &the_lolnd); + LASSERT(!lolnd_instanced); lolnd_instanced = 1; - return (0); + return 0; } lnd_t the_lolnd = { diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c index afb81755cbad..6db8774ff7b7 100644 --- a/drivers/staging/lustre/lnet/lnet/module.c +++ b/drivers/staging/lustre/lnet/lnet/module.c @@ -37,14 +37,14 @@ #define DEBUG_SUBSYSTEM S_LNET #include <linux/lnet/lib-lnet.h> -static int config_on_load = 0; +static int config_on_load; CFS_MODULE_PARM(config_on_load, "i", int, 0444, "configure network at module load"); static struct mutex lnet_config_mutex; int -lnet_configure (void *arg) +lnet_configure(void *arg) { /* 'arg' only there so I can be passed to cfs_create_thread() */ int rc = 0; @@ -64,7 +64,7 @@ lnet_configure (void *arg) } int -lnet_unconfigure (void) +lnet_unconfigure(void) { int refcount; @@ -124,7 +124,7 @@ init_lnet(void) } rc = libcfs_register_ioctl(&lnet_ioctl_handler); - LASSERT (rc == 0); + LASSERT(rc == 0); if (config_on_load) { /* Have to schedule a separate thread to avoid deadlocking @@ -141,7 +141,7 @@ fini_lnet(void) int rc; rc = libcfs_deregister_ioctl(&lnet_ioctl_handler); - LASSERT (rc == 0); + LASSERT(rc == 0); LNetFini(); } diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c index cbce662b987b..9a52f25b72e9 100644 --- a/drivers/staging/lustre/lnet/selftest/conrpc.c +++ b/drivers/staging/lustre/lnet/selftest/conrpc.c @@ -75,7 +75,7 @@ lstcon_rpc_done(srpc_client_rpc_t *rpc) if (crpc->crp_stamp == 0) { /* not aborted */ - LASSERT (crpc->crp_status == 0); + LASSERT(crpc->crp_status == 0); crpc->crp_stamp = cfs_time_current(); crpc->crp_status = rpc->crpc_status; @@ -153,7 +153,7 @@ lstcon_rpc_put(lstcon_rpc_t *crpc) srpc_bulk_t *bulk = &crpc->crp_rpc->crpc_bulk; int i; - LASSERT (list_empty(&crpc->crp_link)); + LASSERT(list_empty(&crpc->crp_link)); for (i = 0; i < bulk->bk_niov; i++) { if (bulk->bk_iovs[i].kiov_page == NULL) @@ -187,7 +187,7 @@ lstcon_rpc_post(lstcon_rpc_t *crpc) { lstcon_rpc_trans_t *trans = crpc->crp_trans; - LASSERT (trans != NULL); + LASSERT(trans != NULL); atomic_inc(&trans->tas_remaining); crpc->crp_posted = 1; @@ -289,7 +289,7 @@ lstcon_rpc_trans_abort(lstcon_rpc_trans_t *trans, int error) lstcon_rpc_t *crpc; lstcon_node_t *nd; - list_for_each_entry (crpc, &trans->tas_rpcs_list, crp_link) { + list_for_each_entry(crpc, &trans->tas_rpcs_list, crp_link) { rpc = crpc->crp_rpc; spin_lock(&rpc->crpc_lock); @@ -330,7 +330,7 @@ lstcon_rpc_trans_check(lstcon_rpc_trans_t *trans) !list_empty(&trans->tas_olink)) /* Not an end session RPC */ return 1; - return (atomic_read(&trans->tas_remaining) == 0) ? 1: 0; + return (atomic_read(&trans->tas_remaining) == 0) ? 1 : 0; } int @@ -349,8 +349,8 @@ lstcon_rpc_trans_postwait(lstcon_rpc_trans_t *trans, int timeout) lstcon_rpc_trans_name(trans->tas_opc)); /* post all requests */ - list_for_each_entry (crpc, &trans->tas_rpcs_list, crp_link) { - LASSERT (!crpc->crp_posted); + list_for_each_entry(crpc, &trans->tas_rpcs_list, crp_link) { + LASSERT(!crpc->crp_posted); lstcon_rpc_post(crpc); } @@ -390,8 +390,8 @@ lstcon_rpc_get_reply(lstcon_rpc_t *crpc, srpc_msg_t **msgpp) srpc_client_rpc_t *rpc = crpc->crp_rpc; srpc_generic_reply_t *rep; - LASSERT (nd != NULL && rpc != NULL); - LASSERT (crpc->crp_stamp != 0); + LASSERT(nd != NULL && rpc != NULL); + LASSERT(crpc->crp_stamp != 0); if (crpc->crp_status != 0) { *msgpp = NULL; @@ -427,14 +427,14 @@ lstcon_rpc_trans_stat(lstcon_rpc_trans_t *trans, lstcon_trans_stat_t *stat) srpc_msg_t *rep; int error; - LASSERT (stat != NULL); + LASSERT(stat != NULL); memset(stat, 0, sizeof(*stat)); list_for_each_entry(crpc, &trans->tas_rpcs_list, crp_link) { lstcon_rpc_stat_total(stat, 1); - LASSERT (crpc->crp_stamp != 0); + LASSERT(crpc->crp_stamp != 0); error = lstcon_rpc_get_reply(crpc, &rep); if (error != 0) { @@ -455,8 +455,7 @@ lstcon_rpc_trans_stat(lstcon_rpc_trans_t *trans, lstcon_trans_stat_t *stat) lstcon_session_feats_check(trans->tas_features); } - CDEBUG(D_NET, "transaction %s : success %d, failure %d, total %d, " - "RPC error(%d), Framework error(%d)\n", + CDEBUG(D_NET, "transaction %s : success %d, failure %d, total %d, RPC error(%d), Framework error(%d)\n", lstcon_rpc_trans_name(trans->tas_opc), lstcon_rpc_stat_success(stat, 0), lstcon_rpc_stat_failure(stat, 0), @@ -482,7 +481,7 @@ lstcon_rpc_trans_interpreter(lstcon_rpc_trans_t *trans, struct timeval tv; int error; - LASSERT (head_up != NULL); + LASSERT(head_up != NULL); next = head_up; @@ -498,7 +497,7 @@ lstcon_rpc_trans_interpreter(lstcon_rpc_trans_t *trans, ent = list_entry(next, lstcon_rpc_ent_t, rpe_link); - LASSERT (crpc->crp_stamp != 0); + LASSERT(crpc->crp_stamp != 0); error = lstcon_rpc_get_reply(crpc, &msg); @@ -532,7 +531,9 @@ lstcon_rpc_trans_interpreter(lstcon_rpc_trans_t *trans, if (readent == NULL) continue; - if ((error = readent(trans->tas_opc, msg, ent)) != 0) + error = readent(trans->tas_opc, msg, ent); + + if (error != 0) return error; } @@ -568,19 +569,19 @@ lstcon_rpc_trans_destroy(lstcon_rpc_trans_t *trans) * user wait for them, just abandon them, they will be recycled * in callback */ - LASSERT (crpc->crp_status != 0); + LASSERT(crpc->crp_status != 0); crpc->crp_node = NULL; crpc->crp_trans = NULL; list_del_init(&crpc->crp_link); - count ++; + count++; spin_unlock(&rpc->crpc_lock); atomic_dec(&trans->tas_remaining); } - LASSERT (atomic_read(&trans->tas_remaining) == 0); + LASSERT(atomic_read(&trans->tas_remaining) == 0); list_del(&trans->tas_link); if (!list_empty(&trans->tas_olink)) @@ -669,14 +670,14 @@ lstcon_batrpc_prep(lstcon_node_t *nd, int transop, unsigned feats, brq->bar_bid = tsb->tsb_id; brq->bar_testidx = tsb->tsb_index; brq->bar_opc = transop == LST_TRANS_TSBRUN ? SRPC_BATCH_OPC_RUN : - (transop == LST_TRANS_TSBSTOP ? SRPC_BATCH_OPC_STOP: + (transop == LST_TRANS_TSBSTOP ? SRPC_BATCH_OPC_STOP : SRPC_BATCH_OPC_QUERY); if (transop != LST_TRANS_TSBRUN && transop != LST_TRANS_TSBSTOP) return 0; - LASSERT (tsb->tsb_index == 0); + LASSERT(tsb->tsb_index == 0); batch = (lstcon_batch_t *)tsb; brq->bar_arg = batch->bat_arg; @@ -710,7 +711,7 @@ lstcon_next_id(int idx, int nkiov, lnet_kiov_t *kiov) i = idx / SFW_ID_PER_PAGE; - LASSERT (i < nkiov); + LASSERT(i < nkiov); pid = (lnet_process_id_packed_t *)page_address(kiov[i].kiov_page); @@ -728,9 +729,9 @@ lstcon_dstnodes_prep(lstcon_group_t *grp, int idx, int end; int i = 0; - LASSERT (dist >= 1); - LASSERT (span >= 1); - LASSERT (grp->grp_nnode >= 1); + LASSERT(dist >= 1); + LASSERT(span >= 1); + LASSERT(grp->grp_nnode >= 1); if (span > grp->grp_nnode) return -EINVAL; @@ -741,11 +742,11 @@ lstcon_dstnodes_prep(lstcon_group_t *grp, int idx, list_for_each_entry(ndl, &grp->grp_ndl_list, ndl_link) { nd = ndl->ndl_node; if (i < start) { - i ++; + i++; continue; } - if (i > (end >= start ? end: grp->grp_nnode)) + if (i > (end >= start ? end : grp->grp_nnode)) break; pid = lstcon_next_id((i - start), nkiov, kiov); @@ -866,7 +867,7 @@ lstcon_testrpc_prep(lstcon_node_t *nd, int transop, unsigned feats, bulk->bk_sink = 0; - LASSERT (transop == LST_TRANS_TSBCLIADD); + LASSERT(transop == LST_TRANS_TSBCLIADD); rc = lstcon_dstnodes_prep(test->tes_dst_grp, test->tes_cliidx++, @@ -942,8 +943,7 @@ lstcon_sesnew_stat_reply(lstcon_rpc_trans_t *trans, } if (reply->msg_ses_feats != trans->tas_features) { - CNETERR("Framework features %x from %s is different with " - "features on this transaction: %x\n", + CNETERR("Framework features %x from %s is different with features on this transaction: %x\n", reply->msg_ses_feats, libcfs_nid2str(nd->nd_id.nid), trans->tas_features); status = mksn_rep->mksn_status = EPROTO; @@ -1107,8 +1107,8 @@ lstcon_rpc_trans_ndlist(struct list_head *ndlist, continue; if (rc < 0) { - CDEBUG(D_NET, "Condition error while creating RPC " - " for transaction %d: %d\n", transop, rc); + CDEBUG(D_NET, "Condition error while creating RPC for transaction %d: %d\n", + transop, rc); break; } @@ -1193,7 +1193,7 @@ lstcon_rpc_pinger(void *arg) trans = console_session.ses_ping; - LASSERT (trans != NULL); + LASSERT(trans != NULL); list_for_each_entry(ndl, &console_session.ses_ndl_list, ndl_link) { nd = ndl->ndl_node; @@ -1219,8 +1219,8 @@ lstcon_rpc_pinger(void *arg) crpc = &nd->nd_ping; if (crpc->crp_rpc != NULL) { - LASSERT (crpc->crp_trans == trans); - LASSERT (!list_empty(&crpc->crp_link)); + LASSERT(crpc->crp_trans == trans); + LASSERT(!list_empty(&crpc->crp_link)); spin_lock(&crpc->crp_rpc->crpc_lock); @@ -1264,7 +1264,7 @@ lstcon_rpc_pinger(void *arg) lstcon_rpc_trans_addreq(trans, crpc); lstcon_rpc_post(crpc); - count ++; + count++; } if (console_session.ses_expired) { @@ -1286,8 +1286,8 @@ lstcon_rpc_pinger_start(void) stt_timer_t *ptimer; int rc; - LASSERT (list_empty(&console_session.ses_rpc_freelist)); - LASSERT (atomic_read(&console_session.ses_rpc_counter) == 0); + LASSERT(list_empty(&console_session.ses_rpc_freelist)); + LASSERT(atomic_read(&console_session.ses_rpc_counter) == 0); rc = lstcon_rpc_trans_prep(NULL, LST_TRANS_SESPING, &console_session.ses_ping); @@ -1307,7 +1307,7 @@ lstcon_rpc_pinger_start(void) void lstcon_rpc_pinger_stop(void) { - LASSERT (console_session.ses_shutdown); + LASSERT(console_session.ses_shutdown); stt_del_timer(&console_session.ses_ping_timer); @@ -1330,7 +1330,7 @@ lstcon_rpc_cleanup_wait(void) /* Called with hold of global mutex */ - LASSERT (console_session.ses_shutdown); + LASSERT(console_session.ses_shutdown); while (!list_empty(&console_session.ses_trans_list)) { list_for_each(pacer, &console_session.ses_trans_list) { @@ -1345,8 +1345,7 @@ lstcon_rpc_cleanup_wait(void) mutex_unlock(&console_session.ses_mutex); - CWARN("Session is shutting down, " - "waiting for termination of transactions\n"); + CWARN("Session is shutting down, waiting for termination of transactions\n"); cfs_pause(cfs_time_seconds(1)); mutex_lock(&console_session.ses_mutex); @@ -1356,8 +1355,7 @@ lstcon_rpc_cleanup_wait(void) lst_wait_until((atomic_read(&console_session.ses_rpc_counter) == 0), console_session.ses_rpc_lock, - "Network is not accessible or target is down, " - "waiting for %d console RPCs to being recycled\n", + "Network is not accessible or target is down, waiting for %d console RPCs to being recycled\n", atomic_read(&console_session.ses_rpc_counter)); list_add(&zlist, &console_session.ses_rpc_freelist); @@ -1392,6 +1390,6 @@ lstcon_rpc_module_init(void) void lstcon_rpc_module_fini(void) { - LASSERT (list_empty(&console_session.ses_rpc_freelist)); - LASSERT (atomic_read(&console_session.ses_rpc_counter) == 0); + LASSERT(list_empty(&console_session.ses_rpc_freelist)); + LASSERT(atomic_read(&console_session.ses_rpc_counter) == 0); } diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c index 09e4700af640..f1152e4fbcc4 100644 --- a/drivers/staging/lustre/lnet/selftest/console.c +++ b/drivers/staging/lustre/lnet/selftest/console.c @@ -797,7 +797,7 @@ lstcon_group_info(char *name, lstcon_ndlist_ent_t *gents_p, return rc; } - if (dents_up != 0) { + if (dents_up) { /* verbose query */ rc = lstcon_nodes_getent(&grp->grp_ndl_list, index_p, count_p, dents_up); diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c index 3bf4afb42ffe..82fd363679cb 100644 --- a/drivers/staging/lustre/lnet/selftest/timer.c +++ b/drivers/staging/lustre/lnet/selftest/timer.c @@ -74,14 +74,14 @@ stt_add_timer(stt_timer_t *timer) spin_lock(&stt_data.stt_lock); - LASSERT (stt_data.stt_nthreads > 0); - LASSERT (!stt_data.stt_shuttingdown); - LASSERT (timer->stt_func != NULL); - LASSERT (list_empty(&timer->stt_list)); - LASSERT (cfs_time_after(timer->stt_expires, cfs_time_current_sec())); + LASSERT(stt_data.stt_nthreads > 0); + LASSERT(!stt_data.stt_shuttingdown); + LASSERT(timer->stt_func != NULL); + LASSERT(list_empty(&timer->stt_list)); + LASSERT(cfs_time_after(timer->stt_expires, cfs_time_current_sec())); /* a simple insertion sort */ - list_for_each_prev (pos, STTIMER_SLOT(timer->stt_expires)) { + list_for_each_prev(pos, STTIMER_SLOT(timer->stt_expires)) { stt_timer_t *old = list_entry(pos, stt_timer_t, stt_list); if (cfs_time_aftereq(timer->stt_expires, old->stt_expires)) @@ -102,14 +102,14 @@ stt_add_timer(stt_timer_t *timer) * another CPU. */ int -stt_del_timer (stt_timer_t *timer) +stt_del_timer(stt_timer_t *timer) { int ret = 0; spin_lock(&stt_data.stt_lock); - LASSERT (stt_data.stt_nthreads > 0); - LASSERT (!stt_data.stt_shuttingdown); + LASSERT(stt_data.stt_nthreads > 0); + LASSERT(!stt_data.stt_shuttingdown); if (!list_empty(&timer->stt_list)) { ret = 1; @@ -122,7 +122,7 @@ stt_del_timer (stt_timer_t *timer) /* called with stt_data.stt_lock held */ int -stt_expire_list (struct list_head *slot, cfs_time_t now) +stt_expire_list(struct list_head *slot, cfs_time_t now) { int expired = 0; stt_timer_t *timer; @@ -146,7 +146,7 @@ stt_expire_list (struct list_head *slot, cfs_time_t now) } int -stt_check_timers (cfs_time_t *last) +stt_check_timers(cfs_time_t *last) { int expired = 0; cfs_time_t now; @@ -169,7 +169,7 @@ stt_check_timers (cfs_time_t *last) int -stt_timer_main (void *arg) +stt_timer_main(void *arg) { int rc = 0; UNUSED(arg); @@ -193,7 +193,7 @@ stt_timer_main (void *arg) } int -stt_start_timer_thread (void) +stt_start_timer_thread(void) { struct task_struct *task; @@ -211,7 +211,7 @@ stt_start_timer_thread (void) int -stt_startup (void) +stt_startup(void) { int rc = 0; int i; @@ -227,20 +227,20 @@ stt_startup (void) init_waitqueue_head(&stt_data.stt_waitq); rc = stt_start_timer_thread(); if (rc != 0) - CERROR ("Can't spawn timer thread: %d\n", rc); + CERROR("Can't spawn timer thread: %d\n", rc); return rc; } void -stt_shutdown (void) +stt_shutdown(void) { int i; spin_lock(&stt_data.stt_lock); for (i = 0; i < STTIMER_NSLOTS; i++) - LASSERT (list_empty(&stt_data.stt_hash[i])); + LASSERT(list_empty(&stt_data.stt_hash[i])); stt_data.stt_shuttingdown = 1; diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig index 2156a44d0740..93d59b6a60da 100644 --- a/drivers/staging/lustre/lustre/Kconfig +++ b/drivers/staging/lustre/lustre/Kconfig @@ -16,7 +16,7 @@ config LUSTRE_FS this file system support as a module, choose M here: the module will be called lustre. - To mount Lustre file systems , you also need to install the user space + To mount Lustre file systems, you also need to install the user space mount.lustre and other user space commands which can be found in the lustre-client package, available from http://downloads.whamcloud.com/public/lustre/ diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c index 25099cbe37eb..45315101848c 100644 --- a/drivers/staging/lustre/lustre/fld/fld_cache.c +++ b/drivers/staging/lustre/lustre/fld/fld_cache.c @@ -267,7 +267,7 @@ void fld_cache_punch_hole(struct fld_cache *cache, const seqno_t new_end = range->lsr_end; struct fld_cache_entry *fldt; - OBD_ALLOC_GFP(fldt, sizeof *fldt, GFP_ATOMIC); + OBD_ALLOC_GFP(fldt, sizeof(*fldt), GFP_ATOMIC); if (!fldt) { OBD_FREE_PTR(f_new); /* overlap is not allowed, so dont mess up list. */ diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index edb40afe66f1..c485206fc6c2 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -3096,13 +3096,13 @@ struct cl_io *cl_io_top(struct cl_io *io); void cl_io_print(const struct lu_env *env, void *cookie, lu_printer_t printer, const struct cl_io *io); -#define CL_IO_SLICE_CLEAN(foo_io, base) \ -do { \ - typeof(foo_io) __foo_io = (foo_io); \ +#define CL_IO_SLICE_CLEAN(foo_io, base) \ +do { \ + typeof(foo_io) __foo_io = (foo_io); \ \ - CLASSERT(offsetof(typeof(*__foo_io), base) == 0); \ - memset(&__foo_io->base + 1, 0, \ - (sizeof *__foo_io) - sizeof __foo_io->base); \ + CLASSERT(offsetof(typeof(*__foo_io), base) == 0); \ + memset(&__foo_io->base + 1, 0, \ + sizeof(*__foo_io) - sizeof(__foo_io->base)); \ } while (0) /** @} cl_io */ diff --git a/drivers/staging/lustre/lustre/include/lclient.h b/drivers/staging/lustre/lustre/include/lclient.h index 9d4011f2908b..27316f7b7a70 100644 --- a/drivers/staging/lustre/lustre/include/lclient.h +++ b/drivers/staging/lustre/lustre/include/lclient.h @@ -388,8 +388,8 @@ __u16 ll_dirent_type_get(struct lu_dirent *ent); __u64 cl_fid_build_ino(const struct lu_fid *fid, int api32); __u32 cl_fid_build_gen(const struct lu_fid *fid); -# define CLOBINVRNT(env, clob, expr) \ - ((void)sizeof(env), (void)sizeof(clob), (void)sizeof !!(expr)) +# define CLOBINVRNT(env, clob, expr) \ + ((void)sizeof(env), (void)sizeof(clob), (void)sizeof(!!(expr))) int cl_init_ea_size(struct obd_export *md_exp, struct obd_export *dt_exp); int cl_ocd_update(struct obd_device *host, diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 9243dfab43d3..359c6c1ba68d 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -232,9 +232,6 @@ static inline int ll_namei_to_lookup_intent_flag(int flag) return flag; } -# define ll_mrf_ret void -# define LL_MRF_RETURN(rc) - #include <linux/fs.h> # define ll_umode_t umode_t diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h index 984235ccd3a5..5ca18d016014 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h @@ -831,9 +831,10 @@ static inline void lu_igif_build(struct lu_fid *fid, __u32 ino, __u32 gen) static inline void fid_cpu_to_le(struct lu_fid *dst, const struct lu_fid *src) { /* check that all fields are converted */ - CLASSERT(sizeof *src == - sizeof fid_seq(src) + - sizeof fid_oid(src) + sizeof fid_ver(src)); + CLASSERT(sizeof(*src) == + sizeof(fid_seq(src)) + + sizeof(fid_oid(src)) + + sizeof(fid_ver(src))); dst->f_seq = cpu_to_le64(fid_seq(src)); dst->f_oid = cpu_to_le32(fid_oid(src)); dst->f_ver = cpu_to_le32(fid_ver(src)); @@ -842,9 +843,10 @@ static inline void fid_cpu_to_le(struct lu_fid *dst, const struct lu_fid *src) static inline void fid_le_to_cpu(struct lu_fid *dst, const struct lu_fid *src) { /* check that all fields are converted */ - CLASSERT(sizeof *src == - sizeof fid_seq(src) + - sizeof fid_oid(src) + sizeof fid_ver(src)); + CLASSERT(sizeof(*src) == + sizeof(fid_seq(src)) + + sizeof(fid_oid(src)) + + sizeof(fid_ver(src))); dst->f_seq = le64_to_cpu(fid_seq(src)); dst->f_oid = le32_to_cpu(fid_oid(src)); dst->f_ver = le32_to_cpu(fid_ver(src)); @@ -853,9 +855,10 @@ static inline void fid_le_to_cpu(struct lu_fid *dst, const struct lu_fid *src) static inline void fid_cpu_to_be(struct lu_fid *dst, const struct lu_fid *src) { /* check that all fields are converted */ - CLASSERT(sizeof *src == - sizeof fid_seq(src) + - sizeof fid_oid(src) + sizeof fid_ver(src)); + CLASSERT(sizeof(*src) == + sizeof(fid_seq(src)) + + sizeof(fid_oid(src)) + + sizeof(fid_ver(src))); dst->f_seq = cpu_to_be64(fid_seq(src)); dst->f_oid = cpu_to_be32(fid_oid(src)); dst->f_ver = cpu_to_be32(fid_ver(src)); @@ -864,9 +867,10 @@ static inline void fid_cpu_to_be(struct lu_fid *dst, const struct lu_fid *src) static inline void fid_be_to_cpu(struct lu_fid *dst, const struct lu_fid *src) { /* check that all fields are converted */ - CLASSERT(sizeof *src == - sizeof fid_seq(src) + - sizeof fid_oid(src) + sizeof fid_ver(src)); + CLASSERT(sizeof(*src) == + sizeof(fid_seq(src)) + + sizeof(fid_oid(src)) + + sizeof(fid_ver(src))); dst->f_seq = be64_to_cpu(fid_seq(src)); dst->f_oid = be32_to_cpu(fid_oid(src)); dst->f_ver = be32_to_cpu(fid_ver(src)); @@ -891,9 +895,11 @@ extern void lustre_swab_lu_seq_range(struct lu_seq_range *range); static inline int lu_fid_eq(const struct lu_fid *f0, const struct lu_fid *f1) { /* Check that there is no alignment padding. */ - CLASSERT(sizeof *f0 == - sizeof f0->f_seq + sizeof f0->f_oid + sizeof f0->f_ver); - return memcmp(f0, f1, sizeof *f0) == 0; + CLASSERT(sizeof(*f0) == + sizeof(f0->f_seq) + + sizeof(f0->f_oid) + + sizeof(f0->f_ver)); + return memcmp(f0, f1, sizeof(*f0)) == 0; } #define __diff_normalize(val0, val1) \ @@ -1638,8 +1644,10 @@ static inline void lmm_oi_cpu_to_le(struct ost_id *dst_oi, /* extern void lustre_swab_lov_mds_md(struct lov_mds_md *llm); */ -#define MAX_MD_SIZE (sizeof(struct lov_mds_md) + 4 * sizeof(struct lov_ost_data)) -#define MIN_MD_SIZE (sizeof(struct lov_mds_md) + 1 * sizeof(struct lov_ost_data)) +#define MAX_MD_SIZE \ + (sizeof(struct lov_mds_md) + 4 * sizeof(struct lov_ost_data)) +#define MIN_MD_SIZE \ + (sizeof(struct lov_mds_md) + 1 * sizeof(struct lov_ost_data)) #define XATTR_NAME_ACL_ACCESS "system.posix_acl_access" #define XATTR_NAME_ACL_DEFAULT "system.posix_acl_default" diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h index d9d5814e318d..ff119532dafb 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fid.h +++ b/drivers/staging/lustre/lustre/include/lustre_fid.h @@ -590,7 +590,7 @@ fid_build_pdo_res_name(const struct lu_fid *fid, unsigned int hash, static inline void ostid_build_res_name(struct ost_id *oi, struct ldlm_res_id *name) { - memset(name, 0, sizeof *name); + memset(name, 0, sizeof(*name)); if (fid_seq_is_mdt0(ostid_seq(oi))) { name->name[LUSTRE_RES_ID_SEQ_OFF] = ostid_id(oi); name->name[LUSTRE_RES_ID_VER_OID_OFF] = ostid_seq(oi); diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index a6122559d55d..4fd4af9f29c9 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -177,7 +177,7 @@ static inline int lov_stripe_md_cmp(struct lov_stripe_md *m1, * ->lsm_wire contains padding, but it should be zeroed out during * allocation. */ - return memcmp(&m1->lsm_wire, &m2->lsm_wire, sizeof m1->lsm_wire); + return memcmp(&m1->lsm_wire, &m2->lsm_wire, sizeof(m1->lsm_wire)); } static inline int lov_lum_lsm_cmp(struct lov_user_md *lum, diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index 03e6133ef50f..9697e7faff2f 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -633,8 +633,8 @@ do { \ #define OBD_ALLOC(ptr, size) OBD_ALLOC_GFP(ptr, size, __GFP_IO) #define OBD_ALLOC_WAIT(ptr, size) OBD_ALLOC_GFP(ptr, size, GFP_IOFS) -#define OBD_ALLOC_PTR(ptr) OBD_ALLOC(ptr, sizeof *(ptr)) -#define OBD_ALLOC_PTR_WAIT(ptr) OBD_ALLOC_WAIT(ptr, sizeof *(ptr)) +#define OBD_ALLOC_PTR(ptr) OBD_ALLOC(ptr, sizeof(*(ptr))) +#define OBD_ALLOC_PTR_WAIT(ptr) OBD_ALLOC_WAIT(ptr, sizeof(*(ptr))) #define OBD_CPT_ALLOC_GFP(ptr, cptab, cpt, size, gfp_mask) \ __OBD_MALLOC_VERBOSE(ptr, cptab, cpt, size, gfp_mask) @@ -643,7 +643,7 @@ do { \ OBD_CPT_ALLOC_GFP(ptr, cptab, cpt, size, __GFP_IO) #define OBD_CPT_ALLOC_PTR(ptr, cptab, cpt) \ - OBD_CPT_ALLOC(ptr, cptab, cpt, sizeof *(ptr)) + OBD_CPT_ALLOC(ptr, cptab, cpt, sizeof(*(ptr))) # define __OBD_VMALLOC_VEROBSE(ptr, cptab, cpt, size) \ do { \ @@ -773,7 +773,7 @@ do { \ #define OBD_SLAB_CPT_ALLOC_GFP(ptr, slab, cptab, cpt, size, flags) \ __OBD_SLAB_ALLOC_VERBOSE(ptr, slab, cptab, cpt, size, flags) -#define OBD_FREE_PTR(ptr) OBD_FREE(ptr, sizeof *(ptr)) +#define OBD_FREE_PTR(ptr) OBD_FREE(ptr, sizeof(*(ptr))) #define OBD_SLAB_FREE(ptr, slab, size) \ do { \ @@ -789,19 +789,19 @@ do { \ OBD_SLAB_CPT_ALLOC_GFP(ptr, slab, cptab, cpt, size, __GFP_IO) #define OBD_SLAB_ALLOC_PTR(ptr, slab) \ - OBD_SLAB_ALLOC(ptr, slab, sizeof *(ptr)) + OBD_SLAB_ALLOC(ptr, slab, sizeof(*(ptr))) #define OBD_SLAB_CPT_ALLOC_PTR(ptr, slab, cptab, cpt) \ - OBD_SLAB_CPT_ALLOC(ptr, slab, cptab, cpt, sizeof *(ptr)) + OBD_SLAB_CPT_ALLOC(ptr, slab, cptab, cpt, sizeof(*(ptr))) #define OBD_SLAB_ALLOC_PTR_GFP(ptr, slab, flags) \ - OBD_SLAB_ALLOC_GFP(ptr, slab, sizeof *(ptr), flags) + OBD_SLAB_ALLOC_GFP(ptr, slab, sizeof(*(ptr)), flags) #define OBD_SLAB_CPT_ALLOC_PTR_GFP(ptr, slab, cptab, cpt, flags) \ - OBD_SLAB_CPT_ALLOC_GFP(ptr, slab, cptab, cpt, sizeof *(ptr), flags) + OBD_SLAB_CPT_ALLOC_GFP(ptr, slab, cptab, cpt, sizeof(*(ptr)), flags) #define OBD_SLAB_FREE_PTR(ptr, slab) \ - OBD_SLAB_FREE((ptr), (slab), sizeof *(ptr)) + OBD_SLAB_FREE((ptr), (slab), sizeof(*(ptr))) #define KEY_IS(str) \ (keylen >= (sizeof(str)-1) && memcmp(key, str, (sizeof(str)-1)) == 0) diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c index 8ff38c64b7a1..e60c04d5393a 100644 --- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c +++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c @@ -701,7 +701,7 @@ int ccc_io_one_lock_index(const struct lu_env *env, struct cl_io *io, CDEBUG(D_VFSTRACE, "lock: %d [%lu, %lu]\n", mode, start, end); - memset(&cio->cui_link, 0, sizeof cio->cui_link); + memset(&cio->cui_link, 0, sizeof(cio->cui_link)); if (cio->cui_fd && (cio->cui_fd->fd_flags & LL_FILE_GROUP_LOCKED)) { descr->cld_mode = CLM_GROUP; diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index 6133b3f34718..027617f5083f 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -529,7 +529,7 @@ int ldlm_lock_change_resource(struct ldlm_namespace *ns, struct ldlm_lock *lock, lock_res_nested(oldres, LRT_NEW); } LASSERT(memcmp(new_resid, &oldres->lr_name, - sizeof oldres->lr_name) != 0); + sizeof(oldres->lr_name)) != 0); lock->l_resource = newres; unlock_res(oldres); unlock_res_and_lock(lock); diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index 208751a154b3..8d3dd6dad9b7 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -1115,7 +1115,7 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent, lu_ref_fini(&res->lr_reference); /* We have taken lr_lvb_mutex. Drop it. */ mutex_unlock(&res->lr_lvb_mutex); - OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res); + OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof(*res)); res = hlist_entry(hnode, struct ldlm_resource, lr_hash); /* Synchronize with regard to resource creation. */ @@ -1226,7 +1226,7 @@ int ldlm_resource_putref(struct ldlm_resource *res) cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1); if (ns->ns_lvbo && ns->ns_lvbo->lvbo_free) ns->ns_lvbo->lvbo_free(res); - OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res); + OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof(*res)); return 1; } return 0; @@ -1256,7 +1256,7 @@ int ldlm_resource_putref_locked(struct ldlm_resource *res) */ if (ns->ns_lvbo && ns->ns_lvbo->lvbo_free) ns->ns_lvbo->lvbo_free(res); - OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res); + OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof(*res)); cfs_hash_bd_lock(ns->ns_rs_hash, &bd, 1); return 1; diff --git a/drivers/staging/lustre/lustre/libcfs/hash.c b/drivers/staging/lustre/lustre/libcfs/hash.c index 0dd12c8c91b6..29ce3807fc88 100644 --- a/drivers/staging/lustre/lustre/libcfs/hash.c +++ b/drivers/staging/lustre/lustre/libcfs/hash.c @@ -1965,7 +1965,7 @@ cfs_hash_rehash_worker(cfs_workitem_t *wi) if (bkts != NULL) cfs_hash_buckets_free(bkts, bsize, new_size, old_size); if (rc != 0) - CDEBUG(D_INFO, "early quit of of rehashing: %d\n", rc); + CDEBUG(D_INFO, "early quit of rehashing: %d\n", rc); /* return 1 only if cfs_wi_exit is called */ return rc == -ESRCH; } diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c index ea9e9490031f..0bf8e5d87f1a 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c @@ -167,7 +167,7 @@ static int cfs_access_process_vm(struct task_struct *tsk, unsigned long addr, return 0; down_read(&mm->mmap_sem); - /* ignore errors, just check how much was sucessfully transfered */ + /* ignore errors, just check how much was successfully transferred */ while (len) { int bytes, rc, offset; void *maddr; @@ -227,8 +227,10 @@ int cfs_get_environ(const char *key, char *value, int *val_len) * which is already holding mmap_sem for writes. If some other * thread gets the write lock in the meantime, this thread will * block, but at least it won't deadlock on itself. LU-1735 */ - if (down_read_trylock(&mm->mmap_sem) == 0) + if (down_read_trylock(&mm->mmap_sem) == 0) { + kfree(buffer); return -EDEADLK; + } up_read(&mm->mmap_sem); addr = mm->env_start; diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c index ab1e73168472..cc565b1fb994 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c @@ -137,7 +137,7 @@ void libcfs_run_lbug_upcall(struct libcfs_debug_msg_data *msgdata) char *argv[6]; char buf[32]; - snprintf (buf, sizeof buf, "%d", msgdata->msg_line); + snprintf(buf, sizeof(buf), "%d", msgdata->msg_line); argv[1] = "LBUG"; argv[2] = (char *)msgdata->msg_file; diff --git a/drivers/staging/lustre/lustre/libcfs/prng.c b/drivers/staging/lustre/lustre/libcfs/prng.c index 69224d84bc4b..f87e9e516546 100644 --- a/drivers/staging/lustre/lustre/libcfs/prng.c +++ b/drivers/staging/lustre/lustre/libcfs/prng.c @@ -70,7 +70,7 @@ static unsigned int seed_y = 362436069; * cfs_rand - creates new seeds * * First it creates new seeds from the previous seeds. Then it generates a - * new psuedo random number for use. + * new pseudo random number for use. * * Returns a pseudo-random 32-bit integer */ @@ -84,7 +84,7 @@ unsigned int cfs_rand(void) EXPORT_SYMBOL(cfs_rand); /** - * cfs_srand - sets the inital seed + * cfs_srand - sets the initial seed * @seed1 : (seed_x) should have the most entropy in the low bits of the word * @seed2 : (seed_y) should have the most entropy in the high bits of the word * diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 09844be5eec4..1f079034bd8f 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -743,7 +743,7 @@ int ll_dir_setstripe(struct inode *inode, struct lov_user_md *lump, /* In the following we use the fact that LOV_USER_MAGIC_V1 and LOV_USER_MAGIC_V3 have the same initial fields so we do not - need the make the distiction between the 2 versions */ + need to make the distinction between the 2 versions */ if (set_default && mgc->u.cli.cl_mgc_mgsexp) { char *param = NULL; char *buf; diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index bc534db12431..fb85a58db058 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -364,7 +364,7 @@ static int ll_intent_file_open(struct file *file, void *lmm, that case that lock is also ok */ /* We can also get here if there was cached open handle in revalidate_it * but it disappeared while we were getting from there to ll_file_open. - * But this means this file was closed and immediatelly opened which + * But this means this file was closed and immediately opened which * makes a good candidate for using OPEN lock */ /* If lmmsize & lmm are not 0, we are just setting stripe info * parameters. No need for the open lock */ @@ -2456,8 +2456,8 @@ static int ll_inode_revalidate_fini(struct inode *inode, int rc) if (rc == -ENOENT) { clear_nlink(inode); /* This path cannot be hit for regular files unless in - * case of obscure races, so no need to to validate - * size. */ + * case of obscure races, so no need to validate size. + */ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) return 0; } else if (rc != 0) { @@ -3011,7 +3011,7 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode, /* set layout to file. Unlikely this will fail as old layout was * surely eliminated */ - memset(&conf, 0, sizeof conf); + memset(&conf, 0, sizeof(conf)); conf.coc_opc = OBJECT_CONF_SET; conf.coc_inode = inode; conf.coc_lock = lock; @@ -3034,7 +3034,7 @@ out: ll_get_fsname(inode->i_sb, NULL, 0), inode, PFID(&lli->lli_fid)); - memset(&conf, 0, sizeof conf); + memset(&conf, 0, sizeof(conf)); conf.coc_opc = OBJECT_CONF_WAIT; conf.coc_inode = inode; rc = ll_layout_conf(inode, &conf); diff --git a/drivers/staging/lustre/lustre/llite/llite_close.c b/drivers/staging/lustre/lustre/llite/llite_close.c index 1f5825c87a79..e2996c46b2c0 100644 --- a/drivers/staging/lustre/lustre/llite/llite_close.c +++ b/drivers/staging/lustre/lustre/llite/llite_close.c @@ -159,7 +159,7 @@ void ll_ioepoch_close(struct inode *inode, struct md_op_data *op_data, } if (flags & LLIF_DONE_WRITING) { /* Some pages are still dirty, it is early to send - * DONE_WRITE. Wait untill all pages will be flushed + * DONE_WRITE. Wait until all pages will be flushed * and try DONE_WRITE again later. */ LASSERT(!(lli->lli_flags & LLIF_DONE_WRITING)); lli->lli_flags |= LLIF_DONE_WRITING; diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index b868c2bd58d2..fd584ff7e2df 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1973,10 +1973,10 @@ void ll_umount_begin(struct super_block *sb) OBD_ALLOC_PTR(ioc_data); if (ioc_data) { obd_iocontrol(IOC_OSC_SET_ACTIVE, sbi->ll_md_exp, - sizeof *ioc_data, ioc_data, NULL); + sizeof(*ioc_data), ioc_data, NULL); obd_iocontrol(IOC_OSC_SET_ACTIVE, sbi->ll_dt_exp, - sizeof *ioc_data, ioc_data, NULL); + sizeof(*ioc_data), ioc_data, NULL); OBD_FREE_PTR(ioc_data); } diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c index 2340458b8a04..e2421ea61352 100644 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ b/drivers/staging/lustre/lustre/llite/lloop.c @@ -337,8 +337,7 @@ static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req) return count; } -static ll_mrf_ret -loop_make_request(struct request_queue *q, struct bio *old_bio) +static void loop_make_request(struct request_queue *q, struct bio *old_bio) { struct lloop_device *lo = q->queuedata; int rw = bio_rw(old_bio); @@ -366,10 +365,9 @@ loop_make_request(struct request_queue *q, struct bio *old_bio) goto err; } loop_add_bio(lo, old_bio); - LL_MRF_RETURN(0); + return; err: cfs_bio_io_error(old_bio, old_bio->bi_size); - LL_MRF_RETURN(0); } diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index ae0dc441d1d9..e9ba38a553cf 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -717,7 +717,7 @@ int ll_readahead(const struct lu_env *env, struct cl_io *io, lli = ll_i2info(inode); clob = lli->lli_clob; - memset(ria, 0, sizeof *ria); + memset(ria, 0, sizeof(*ria)); cl_object_attr_lock(clob); ret = cl_object_attr_get(env, clob, attr); diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c index 96c29ad2fc8c..7e3e0967993b 100644 --- a/drivers/staging/lustre/lustre/llite/rw26.c +++ b/drivers/staging/lustre/lustre/llite/rw26.c @@ -202,11 +202,8 @@ static inline int ll_get_user_pages(int rw, unsigned long user_addr, OBD_ALLOC_LARGE(*pages, *max_pages * sizeof(**pages)); if (*pages) { - down_read(¤t->mm->mmap_sem); - result = get_user_pages(current, current->mm, user_addr, - *max_pages, (rw == READ), 0, *pages, - NULL); - up_read(¤t->mm->mmap_sem); + result = get_user_pages_fast(user_addr, *max_pages, + (rw == READ), *pages); if (unlikely(result <= 0)) OBD_FREE_LARGE(*pages, *max_pages * sizeof(**pages)); } diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 8eaa38e91b99..f6b5f4b95f37 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -647,7 +647,7 @@ static void ll_post_statahead(struct ll_statahead_info *sai) */ LASSERT(fid_is_zero(&minfo->mi_data.op_fid2)); - /* XXX: No fid in reply, this is probaly cross-ref case. + /* XXX: No fid in reply, this is probably cross-ref case. * SA can't handle it yet. */ if (body->valid & OBD_MD_MDS) GOTO(out, rc = -EAGAIN); diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c index a4006ef46ad2..099cebb05e44 100644 --- a/drivers/staging/lustre/lustre/lov/lov_dev.c +++ b/drivers/staging/lustre/lustre/lov/lov_dev.c @@ -286,7 +286,7 @@ static void lov_emerg_free(struct lov_device_emerg **emrg, int nr) OBD_FREE_PTR(em); } } - OBD_FREE(emrg, nr * sizeof emrg[0]); + OBD_FREE(emrg, nr * sizeof(emrg[0])); } static struct lu_device *lov_device_free(const struct lu_env *env, @@ -297,7 +297,7 @@ static struct lu_device *lov_device_free(const struct lu_env *env, cl_device_fini(lu2cl_dev(d)); if (ld->ld_target != NULL) - OBD_FREE(ld->ld_target, nr * sizeof ld->ld_target[0]); + OBD_FREE(ld->ld_target, nr * sizeof(ld->ld_target[0])); if (ld->ld_emrg != NULL) lov_emerg_free(ld->ld_emrg, nr); OBD_FREE_PTR(ld); @@ -321,7 +321,7 @@ static struct lov_device_emerg **lov_emerg_alloc(int nr) int i; int result; - OBD_ALLOC(emerg, nr * sizeof emerg[0]); + OBD_ALLOC(emerg, nr * sizeof(emerg[0])); if (emerg == NULL) return ERR_PTR(-ENOMEM); for (result = i = 0; i < nr && result == 0; i++) { @@ -361,7 +361,7 @@ static int lov_expand_targets(const struct lu_env *env, struct lov_device *dev) if (sub_size < tgt_size) { struct lovsub_device **newd; struct lov_device_emerg **emerg; - const size_t sz = sizeof newd[0]; + const size_t sz = sizeof(newd[0]); emerg = lov_emerg_alloc(tgt_size); if (IS_ERR(emerg)) diff --git a/drivers/staging/lustre/lustre/lov/lov_internal.h b/drivers/staging/lustre/lustre/lov/lov_internal.h index 16770d14ee04..9870d360a15a 100644 --- a/drivers/staging/lustre/lustre/lov/lov_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_internal.h @@ -124,7 +124,7 @@ static inline void lov_llh_put(struct lov_lock_handles *llh) if (atomic_read(&llh->llh_refcount)) return; - OBD_FREE_RCU(llh, sizeof *llh + + OBD_FREE_RCU(llh, sizeof(*llh) + sizeof(*llh->llh_handles) * llh->llh_stripe_count, &llh->llh_handle); } diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c index b611aa4e9dcb..5be0e2c243b0 100644 --- a/drivers/staging/lustre/lustre/lov/lov_io.c +++ b/drivers/staging/lustre/lustre/lov/lov_io.c @@ -282,7 +282,7 @@ static int lov_io_subio_init(const struct lu_env *env, struct lov_io *lio, * when writing a page. -jay */ OBD_ALLOC_LARGE(lio->lis_subs, - lsm->lsm_stripe_count * sizeof lio->lis_subs[0]); + lsm->lsm_stripe_count * sizeof(lio->lis_subs[0])); if (lio->lis_subs != NULL) { lio->lis_nr_subios = lio->lis_stripe_count; lio->lis_single_subio_index = -1; @@ -356,7 +356,7 @@ static void lov_io_fini(const struct lu_env *env, const struct cl_io_slice *ios) for (i = 0; i < lio->lis_nr_subios; i++) lov_io_sub_fini(env, lio, &lio->lis_subs[i]); OBD_FREE_LARGE(lio->lis_subs, - lio->lis_nr_subios * sizeof lio->lis_subs[0]); + lio->lis_nr_subios * sizeof(lio->lis_subs[0])); lio->lis_nr_subios = 0; } diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c index ec297e87c2a2..7682aeb3fa6a 100644 --- a/drivers/staging/lustre/lustre/lov/lov_lock.c +++ b/drivers/staging/lustre/lustre/lov/lov_lock.c @@ -313,7 +313,7 @@ static int lov_lock_sub_init(const struct lu_env *env, nr++; } LASSERT(nr > 0); - OBD_ALLOC_LARGE(lck->lls_sub, nr * sizeof lck->lls_sub[0]); + OBD_ALLOC_LARGE(lck->lls_sub, nr * sizeof(lck->lls_sub[0])); if (lck->lls_sub == NULL) return -ENOMEM; @@ -474,7 +474,7 @@ static void lov_lock_fini(const struct lu_env *env, */ LASSERT(lck->lls_sub[i].sub_lock == NULL); OBD_FREE_LARGE(lck->lls_sub, - lck->lls_nr * sizeof lck->lls_sub[0]); + lck->lls_nr * sizeof(lck->lls_sub[0])); } OBD_SLAB_FREE_PTR(lck, lov_lock_kmem); } diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c index 84e55ce3ccd2..cf2fa8abfb1d 100644 --- a/drivers/staging/lustre/lustre/lov/lov_object.c +++ b/drivers/staging/lustre/lustre/lov/lov_object.c @@ -214,7 +214,7 @@ static int lov_init_raid0(const struct lu_env *env, r0->lo_nr = lsm->lsm_stripe_count; LASSERT(r0->lo_nr <= lov_targets_nr(dev)); - OBD_ALLOC_LARGE(r0->lo_sub, r0->lo_nr * sizeof r0->lo_sub[0]); + OBD_ALLOC_LARGE(r0->lo_sub, r0->lo_nr * sizeof(r0->lo_sub[0])); if (r0->lo_sub != NULL) { result = 0; subconf->coc_inode = conf->coc_inode; @@ -368,7 +368,7 @@ static void lov_fini_raid0(const struct lu_env *env, struct lov_object *lov, struct lov_layout_raid0 *r0 = &state->raid0; if (r0->lo_sub != NULL) { - OBD_FREE_LARGE(r0->lo_sub, r0->lo_nr * sizeof r0->lo_sub[0]); + OBD_FREE_LARGE(r0->lo_sub, r0->lo_nr * sizeof(r0->lo_sub[0])); r0->lo_sub = NULL; } diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c index 55ec26778f80..2f80833f164a 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pack.c +++ b/drivers/staging/lustre/lustre/lov/lov_pack.c @@ -630,7 +630,7 @@ int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm, /* FIXME: Bug 1185 - copy fields properly when structs change */ /* struct lov_user_md_v3 and struct lov_mds_md_v3 must be the same */ CLASSERT(sizeof(lum) == sizeof(struct lov_mds_md_v3)); - CLASSERT(sizeof lum.lmm_objects[0] == sizeof lmmk->lmm_objects[0]); + CLASSERT(sizeof(lum.lmm_objects[0]) == sizeof(lmmk->lmm_objects[0])); if ((cpu_to_le32(LOV_MAGIC) != LOV_MAGIC) && ((lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) || diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c index 61e6d0b46c98..f80e62646683 100644 --- a/drivers/staging/lustre/lustre/lov/lov_request.c +++ b/drivers/staging/lustre/lustre/lov/lov_request.c @@ -245,7 +245,7 @@ int lov_update_enqueue_set(struct lov_request *req, __u32 mode, int rc) osc_update_enqueue(lov_lockhp, loi, oi->oi_flags, &req->rq_oi.oi_md->lsm_oinfo[0]->loi_lvb, mode, rc); if (rc == ELDLM_LOCK_ABORTED && (oi->oi_flags & LDLM_FL_HAS_INTENT)) - memset(lov_lockhp, 0, sizeof *lov_lockhp); + memset(lov_lockhp, 0, sizeof(*lov_lockhp)); rc = lov_update_enqueue_lov(set->set_exp, lov_lockhp, loi, oi->oi_flags, req->rq_idx, &oi->oi_md->lsm_oi, rc); lov_stripe_unlock(oi->oi_md); @@ -343,7 +343,7 @@ static struct lov_lock_handles *lov_llh_new(struct lov_stripe_md *lsm) { struct lov_lock_handles *llh; - OBD_ALLOC(llh, sizeof *llh + + OBD_ALLOC(llh, sizeof(*llh) + sizeof(*llh->llh_handles) * lsm->lsm_stripe_count); if (llh == NULL) return NULL; diff --git a/drivers/staging/lustre/lustre/lvfs/fsfilt.c b/drivers/staging/lustre/lustre/lvfs/fsfilt.c index e86df7356cb1..0d6ed69ddb22 100644 --- a/drivers/staging/lustre/lustre/lvfs/fsfilt.c +++ b/drivers/staging/lustre/lustre/lvfs/fsfilt.c @@ -50,9 +50,8 @@ static struct fsfilt_operations *fsfilt_search_type(const char *type) list_for_each(p, &fsfilt_types) { found = list_entry(p, struct fsfilt_operations, fs_list); - if (!strcmp(found->fs_type, type)) { + if (!strcmp(found->fs_type, type)) return found; - } } return NULL; } @@ -62,7 +61,8 @@ int fsfilt_register_ops(struct fsfilt_operations *fs_ops) struct fsfilt_operations *found; /* lock fsfilt_types list */ - if ((found = fsfilt_search_type(fs_ops->fs_type))) { + found = fsfilt_search_type(fs_ops->fs_type); + if (found) { if (found != fs_ops) { CERROR("different operations for type %s\n", fs_ops->fs_type); @@ -103,14 +103,16 @@ struct fsfilt_operations *fsfilt_get_ops(const char *type) struct fsfilt_operations *fs_ops; /* lock fsfilt_types list */ - if (!(fs_ops = fsfilt_search_type(type))) { + fs_ops = fsfilt_search_type(type); + if (!fs_ops) { char name[32]; int rc; snprintf(name, sizeof(name) - 1, "fsfilt_%s", type); name[sizeof(name) - 1] = '\0'; - if (!(rc = request_module("%s", name))) { + rc = request_module("%s", name); + if (!rc) { fs_ops = fsfilt_search_type(type); CDEBUG(D_INFO, "Loaded module '%s'\n", name); if (!fs_ops) diff --git a/drivers/staging/lustre/lustre/lvfs/lvfs_lib.c b/drivers/staging/lustre/lustre/lvfs/lvfs_lib.c index 97a8be2300dd..b21e40cdacab 100644 --- a/drivers/staging/lustre/lustre/lvfs/lvfs_lib.c +++ b/drivers/staging/lustre/lustre/lvfs/lvfs_lib.c @@ -154,11 +154,10 @@ int lprocfs_stats_alloc_one(struct lprocfs_stats *stats, unsigned int cpuid) spin_lock(&stats->ls_lock); if (stats->ls_biggest_alloc_num <= cpuid) stats->ls_biggest_alloc_num = cpuid + 1; - if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) { + if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) spin_unlock_irqrestore(&stats->ls_lock, flags); - } else { + else spin_unlock(&stats->ls_lock); - } } /* initialize the ls_percpu[cpuid] non-zero counter */ for (i = 0; i < stats->ls_num; ++i) { diff --git a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c index 18e1b47a1d65..ea3771550788 100644 --- a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c +++ b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c @@ -80,7 +80,8 @@ static void push_group_info(struct lvfs_run_ctxt *save, struct cred *cred; task_lock(current); save->group_info = current_cred()->group_info; - if ((cred = prepare_creds())) { + cred = prepare_creds(); + if (cred) { cred->group_info = ginfo; commit_creds(cred); } @@ -96,7 +97,8 @@ static void pop_group_info(struct lvfs_run_ctxt *save, } else { struct cred *cred; task_lock(current); - if ((cred = prepare_creds())) { + cred = prepare_creds(); + if (cred) { cred->group_info = save->group_info; commit_creds(cred); } @@ -137,7 +139,8 @@ void push_ctxt(struct lvfs_run_ctxt *save, struct lvfs_run_ctxt *new_ctx, save->luc.luc_fsgid = current_fsgid(); save->luc.luc_cap = current_cap(); - if ((cred = prepare_creds())) { + cred = prepare_creds(); + if (cred) { cred->uid = uc->luc_uid; cred->gid = uc->luc_gid; cred->fsuid = uc->luc_fsuid; @@ -180,7 +183,8 @@ void pop_ctxt(struct lvfs_run_ctxt *saved, struct lvfs_run_ctxt *new_ctx, current->fs->umask = saved->luc.luc_umask; if (uc) { struct cred *cred; - if ((cred = prepare_creds())) { + cred = prepare_creds(); + if (cred) { cred->uid = saved->luc.luc_uid; cred->gid = saved->luc.luc_gid; cred->fsuid = saved->luc.luc_fsuid; @@ -253,32 +257,32 @@ __s64 lprocfs_read_helper(struct lprocfs_counter *lc, return 0; switch (field) { - case LPROCFS_FIELDS_FLAGS_CONFIG: - ret = header->lc_config; - break; - case LPROCFS_FIELDS_FLAGS_SUM: - ret = lc->lc_sum; - if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) - ret += lc->lc_sum_irq; - break; - case LPROCFS_FIELDS_FLAGS_MIN: - ret = lc->lc_min; - break; - case LPROCFS_FIELDS_FLAGS_MAX: - ret = lc->lc_max; - break; - case LPROCFS_FIELDS_FLAGS_AVG: - ret = (lc->lc_max - lc->lc_min) / 2; - break; - case LPROCFS_FIELDS_FLAGS_SUMSQUARE: - ret = lc->lc_sumsquare; - break; - case LPROCFS_FIELDS_FLAGS_COUNT: - ret = lc->lc_count; - break; - default: - break; - }; + case LPROCFS_FIELDS_FLAGS_CONFIG: + ret = header->lc_config; + break; + case LPROCFS_FIELDS_FLAGS_SUM: + ret = lc->lc_sum; + if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) + ret += lc->lc_sum_irq; + break; + case LPROCFS_FIELDS_FLAGS_MIN: + ret = lc->lc_min; + break; + case LPROCFS_FIELDS_FLAGS_MAX: + ret = lc->lc_max; + break; + case LPROCFS_FIELDS_FLAGS_AVG: + ret = (lc->lc_max - lc->lc_min) / 2; + break; + case LPROCFS_FIELDS_FLAGS_SUMSQUARE: + ret = lc->lc_sumsquare; + break; + case LPROCFS_FIELDS_FLAGS_COUNT: + ret = lc->lc_count; + break; + default: + break; + } return ret; } diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c index 426979341554..e048500edd60 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_io.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c @@ -1387,7 +1387,7 @@ static void cl_req_free(const struct lu_env *env, struct cl_req *req) cl_object_put(env, obj); } } - OBD_FREE(req->crq_o, req->crq_nrobjs * sizeof req->crq_o[0]); + OBD_FREE(req->crq_o, req->crq_nrobjs * sizeof(req->crq_o[0])); } OBD_FREE_PTR(req); } @@ -1452,7 +1452,7 @@ struct cl_req *cl_req_alloc(const struct lu_env *env, struct cl_page *page, if (req != NULL) { int result; - OBD_ALLOC(req->crq_o, nr_objects * sizeof req->crq_o[0]); + OBD_ALLOC(req->crq_o, nr_objects * sizeof(req->crq_o[0])); if (req->crq_o != NULL) { req->crq_nrobjs = nr_objects; req->crq_type = crt; @@ -1642,7 +1642,7 @@ int cl_sync_io_wait(const struct lu_env *env, struct cl_io *io, cpu_relax(); } - POISON(anchor, 0x5a, sizeof *anchor); + POISON(anchor, 0x5a, sizeof(*anchor)); return rc; } EXPORT_SYMBOL(cl_sync_io_wait); diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index b1024a6d37dd..4afd962cdb64 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -178,7 +178,7 @@ EXPORT_SYMBOL(obd_alloc_fail); static inline void obd_data2conn(struct lustre_handle *conn, struct obd_ioctl_data *data) { - memset(conn, 0, sizeof *conn); + memset(conn, 0, sizeof(*conn)); conn->cookie = data->ioc_cookie; } diff --git a/drivers/staging/lustre/lustre/obdclass/llog_test.c b/drivers/staging/lustre/lustre/obdclass/llog_test.c index d9e6d12215f9..178f89eccab1 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_test.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_test.c @@ -242,7 +242,7 @@ static int llog_test_3(const struct lu_env *env, struct obd_device *obd, hdr.lrh_len = 8; hdr.lrh_type = OBD_CFG_REC; - memset(buf, 0, sizeof buf); + memset(buf, 0, sizeof(buf)); rc = llog_write(env, llh, &hdr, NULL, 0, buf, -1); if (rc < 0) { CERROR("3b: write 10 records failed at #%d: %d\n", @@ -277,8 +277,8 @@ static int llog_test_3(const struct lu_env *env, struct obd_device *obd, char buf_even[24]; char buf_odd[32]; - memset(buf_odd, 0, sizeof buf_odd); - memset(buf_even, 0, sizeof buf_even); + memset(buf_odd, 0, sizeof(buf_odd)); + memset(buf_even, 0, sizeof(buf_even)); if ((i % 2) == 0) { hdr.lrh_len = 24; hdr.lrh_type = OBD_CFG_REC; diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index 3a3d5bc5a628..e8f260781c0e 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -980,7 +980,7 @@ int lu_site_init(struct lu_site *s, struct lu_device *top) int bits; int i; - memset(s, 0, sizeof *s); + memset(s, 0, sizeof(*s)); bits = lu_htable_order(); snprintf(name, 16, "lu_site_%s", top->ld_type->ldt_name); for (bits = min(max(LU_SITE_BITS_MIN, bits), LU_SITE_BITS_MAX); @@ -1110,7 +1110,7 @@ int lu_device_init(struct lu_device *d, struct lu_device_type *t) { if (t->ldt_device_nr++ == 0 && t->ldt_ops->ldto_start != NULL) t->ldt_ops->ldto_start(t); - memset(d, 0, sizeof *d); + memset(d, 0, sizeof(*d)); atomic_set(&d->ld_ref, 0); d->ld_type = t; lu_ref_init(&d->ld_reference); @@ -1206,7 +1206,7 @@ EXPORT_SYMBOL(lu_object_add); */ int lu_object_header_init(struct lu_object_header *h) { - memset(h, 0, sizeof *h); + memset(h, 0, sizeof(*h)); atomic_set(&h->loh_ref, 1); INIT_HLIST_NODE(&h->loh_hash); INIT_LIST_HEAD(&h->loh_lru); @@ -1525,7 +1525,7 @@ static void keys_fini(struct lu_context *ctx) for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) key_fini(ctx, i); - OBD_FREE(ctx->lc_value, ARRAY_SIZE(lu_keys) * sizeof ctx->lc_value[0]); + OBD_FREE(ctx->lc_value, ARRAY_SIZE(lu_keys) * sizeof(ctx->lc_value[0])); ctx->lc_value = NULL; } @@ -1574,7 +1574,8 @@ static int keys_fill(struct lu_context *ctx) static int keys_init(struct lu_context *ctx) { - OBD_ALLOC(ctx->lc_value, ARRAY_SIZE(lu_keys) * sizeof ctx->lc_value[0]); + OBD_ALLOC(ctx->lc_value, + ARRAY_SIZE(lu_keys) * sizeof(ctx->lc_value[0])); if (likely(ctx->lc_value != NULL)) return keys_fill(ctx); @@ -1588,7 +1589,7 @@ int lu_context_init(struct lu_context *ctx, __u32 tags) { int rc; - memset(ctx, 0, sizeof *ctx); + memset(ctx, 0, sizeof(*ctx)); ctx->lc_state = LCS_INITIALIZED; ctx->lc_tags = tags; if (tags & LCT_REMEMBER) { diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index d0a64ff53581..73e2571f463f 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -417,7 +417,7 @@ int class_attach(struct lustre_cfg *lcfg) /* do the attach */ if (OBP(obd, attach)) { - rc = OBP(obd,attach)(obd, sizeof *lcfg, lcfg); + rc = OBP(obd, attach)(obd, sizeof(*lcfg), lcfg); if (rc) GOTO(out, rc = -EINVAL); } @@ -900,7 +900,7 @@ void class_del_profile(const char *prof) OBD_FREE(lprof->lp_dt, strlen(lprof->lp_dt) + 1); if (lprof->lp_md) OBD_FREE(lprof->lp_md, strlen(lprof->lp_md) + 1); - OBD_FREE(lprof, sizeof *lprof); + OBD_FREE(lprof, sizeof(*lprof)); } } EXPORT_SYMBOL(class_del_profile); @@ -916,7 +916,7 @@ void class_del_profiles(void) OBD_FREE(lprof->lp_dt, strlen(lprof->lp_dt) + 1); if (lprof->lp_md) OBD_FREE(lprof->lp_md, strlen(lprof->lp_md) + 1); - OBD_FREE(lprof, sizeof *lprof); + OBD_FREE(lprof, sizeof(*lprof)); } } EXPORT_SYMBOL(class_del_profiles); diff --git a/drivers/staging/lustre/lustre/obdclass/uuid.c b/drivers/staging/lustre/lustre/obdclass/uuid.c index af5f27f82bc5..e87a19900770 100644 --- a/drivers/staging/lustre/lustre/obdclass/uuid.c +++ b/drivers/staging/lustre/lustre/obdclass/uuid.c @@ -48,7 +48,7 @@ static inline __u32 consume(int nob, __u8 **ptr) { __u32 value; - LASSERT(nob <= sizeof value); + LASSERT(nob <= sizeof(value)); for (value = 0; nob > 0; --nob) value = (value << 8) | *((*ptr)++); @@ -61,7 +61,7 @@ static void uuid_unpack(class_uuid_t in, __u16 *uu, int nr) { __u8 *ptr = in; - LASSERT(nr * sizeof *uu == sizeof(class_uuid_t)); + LASSERT(nr * sizeof(*uu) == sizeof(class_uuid_t)); while (nr-- > 0) CONSUME(uu[nr], &ptr); diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index c8b43442dc74..1fb0ac4e920d 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -1089,7 +1089,7 @@ static struct echo_object *cl_echo_object_find(struct echo_device *d, } else { struct lustre_md *md; md = &info->eti_md; - memset(md, 0, sizeof *md); + memset(md, 0, sizeof(*md)); md->lsm = lsm; conf->eoc_cl.u.coc_md = md; } diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index 5d7bdbfc871a..c90abfbb1d7a 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -862,7 +862,7 @@ static int osc_ldlm_glimpse_ast(struct ldlm_lock *dlmlock, void *data) cap = &req->rq_pill; req_capsule_extend(cap, &RQF_LDLM_GL_CALLBACK); req_capsule_set_size(cap, &RMF_DLM_LVB, RCL_SERVER, - sizeof *lvb); + sizeof(*lvb)); result = req_capsule_server_pack(cap); if (result == 0) { lvb = req_capsule_server_get(cap, &RMF_DLM_LVB); diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index d272322b29b6..6c20b8ecfb82 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -245,7 +245,7 @@ static int osc_page_cache_add(const struct lu_env *env, void osc_index2policy(ldlm_policy_data_t *policy, const struct cl_object *obj, pgoff_t start, pgoff_t end) { - memset(policy, 0, sizeof *policy); + memset(policy, 0, sizeof(*policy)); policy->l_extent.start = cl_offset(obj, start); policy->l_extent.end = cl_offset(obj, end + 1) - 1; } diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index ee6707a5ea9d..cb197782d9a3 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -2554,7 +2554,7 @@ int osc_enqueue_base(struct obd_export *exp, struct ldlm_res_id *res_id, } req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, - sizeof *lvb); + sizeof(*lvb)); ptlrpc_request_set_replen(req); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 810a458caed7..c2ab0c8c4d42 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -817,7 +817,7 @@ struct ptlrpc_request_set *ptlrpc_prep_set(void) { struct ptlrpc_request_set *set; - OBD_ALLOC(set, sizeof *set); + OBD_ALLOC(set, sizeof(*set)); if (!set) return NULL; atomic_set(&set->set_refcount, 1); @@ -2690,7 +2690,7 @@ int ptlrpc_replay_req(struct ptlrpc_request *req) LASSERT (sizeof (*aa) <= sizeof (req->rq_async_args)); aa = ptlrpc_req_async_args(req); - memset(aa, 0, sizeof *aa); + memset(aa, 0, sizeof(*aa)); /* Prepare request to be resent with ptlrpcd */ aa->praa_old_state = req->rq_send_state; diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index 5ca69aec72e1..7b96a0e88cdb 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -682,7 +682,7 @@ int ptlrpc_connect_import(struct obd_import *imp) CLASSERT(sizeof (*aa) <= sizeof (request->rq_async_args)); aa = ptlrpc_req_async_args(request); - memset(aa, 0, sizeof *aa); + memset(aa, 0, sizeof(*aa)); aa->pcaa_peer_committed = committed_before_reconnect; aa->pcaa_initial_connect = initial_connect; diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c index 2f55ce26ccba..d0a6e5689227 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/layout.c +++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c @@ -1669,7 +1669,7 @@ void req_capsule_init(struct req_capsule *pill, if (req != NULL && pill == &req->rq_pill && req->rq_pill_init) return; - memset(pill, 0, sizeof *pill); + memset(pill, 0, sizeof(*pill)); pill->rc_req = req; pill->rc_loc = location; req_capsule_init_area(pill); diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index 6547f46a7729..316103ab7c3c 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -207,7 +207,7 @@ static void enc_pools_release_free_pages(long npages) p_idx++; g_idx = 0; } - }; + } /* free unused pools */ while (p_idx_max1 < p_idx_max2) { diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index acf75f3873d1..21de868da522 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -263,7 +263,7 @@ static struct ptlrpc_hr_service ptlrpc_hr; */ static void rs_batch_init(struct rs_batch *b) { - memset(b, 0, sizeof *b); + memset(b, 0, sizeof(*b)); INIT_LIST_HEAD(&b->rsb_replies); } @@ -1306,12 +1306,12 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req) } newdl = cfs_time_current_sec() + at_get(&svcpt->scp_at_estimate); - OBD_ALLOC(reqcopy, sizeof *reqcopy); + OBD_ALLOC(reqcopy, sizeof(*reqcopy)); if (reqcopy == NULL) return -ENOMEM; OBD_ALLOC_LARGE(reqmsg, req->rq_reqlen); if (!reqmsg) { - OBD_FREE(reqcopy, sizeof *reqcopy); + OBD_FREE(reqcopy, sizeof(*reqcopy)); return -ENOMEM; } @@ -1370,7 +1370,7 @@ out_put: out: sptlrpc_svc_ctx_decref(reqcopy); OBD_FREE_LARGE(reqmsg, req->rq_reqlen); - OBD_FREE(reqcopy, sizeof *reqcopy); + OBD_FREE(reqcopy, sizeof(*reqcopy)); return rc; } diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 46ed83245035..6f756830c421 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -15,6 +15,8 @@ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -34,10 +36,9 @@ static unsigned int assume_endura; module_param(assume_endura, int, 0644); -MODULE_PARM_DESC(assume_endura, "when probing fails, " - "hardware is a Pelco Endura"); +MODULE_PARM_DESC(assume_endura, + "when probing fails, hardware is a Pelco Endura"); -/* #define GO7007_USB_DEBUG */ /* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */ #define HPI_STATUS_ADDR 0xFFF4 @@ -662,9 +663,7 @@ static int go7007_usb_interface_reset(struct go7007 *go) if (usb->board->flags & GO7007_USB_EZUSB) { /* Reset buffer in EZ-USB */ -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG "go7007-usb: resetting EZ-USB buffers\n"); -#endif + pr_debug("resetting EZ-USB buffers\n"); if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 || go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0) return -1; @@ -678,8 +677,7 @@ static int go7007_usb_interface_reset(struct go7007 *go) /* Wait for an interrupt to indicate successful hardware reset */ if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || (intr_val & ~0x1) != 0x55aa) { - printk(KERN_ERR - "go7007-usb: unable to reset the USB interface\n"); + pr_err("unable to reset the USB interface\n"); return -1; } return 0; @@ -693,10 +691,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, u16 status_reg = 0; int timeout = 500; -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG - "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); -#endif + pr_debug("WriteInterrupt: %04x %04x\n", addr, data); for (i = 0; i < 100; ++i) { r = usb_control_msg(usb->usbdev, @@ -714,9 +709,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, if (r < 0) goto write_int_error; if (i == 100) { - printk(KERN_ERR - "go7007-usb: device is hung, status reg = 0x%04x\n", - status_reg); + pr_err("device is hung, status reg = 0x%04x\n", status_reg); return -1; } r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12, @@ -732,7 +725,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, return 0; write_int_error: - printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); + pr_err("error in WriteInterrupt: %d\n", r); return r; } @@ -743,10 +736,7 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go, int r; int timeout = 500; -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG - "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); -#endif + pr_debug("WriteInterrupt: %04x %04x\n", addr, data); go->usb_buf[0] = data & 0xff; go->usb_buf[1] = data >> 8; @@ -757,7 +747,7 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa, 0xf0f0, go->usb_buf, 8, timeout); if (r < 0) { - printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); + pr_err("error in WriteInterrupt: %d\n", r); return r; } return 0; @@ -772,23 +762,19 @@ static void go7007_usb_readinterrupt_complete(struct urb *urb) if (status) { if (status != -ESHUTDOWN && go->status != STATUS_SHUTDOWN) { - printk(KERN_ERR - "go7007-usb: error in read interrupt: %d\n", - urb->status); + pr_err("error in read interrupt: %d\n", urb->status); } else { wake_up(&go->interrupt_waitq); return; } } else if (urb->actual_length != urb->transfer_buffer_length) { - printk(KERN_ERR "go7007-usb: short read in interrupt pipe!\n"); + pr_err("short read in interrupt pipe!\n"); } else { go->interrupt_available = 1; go->interrupt_data = __le16_to_cpu(regs[0]); go->interrupt_value = __le16_to_cpu(regs[1]); -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG "go7007-usb: ReadInterrupt: %04x %04x\n", + pr_debug("ReadInterrupt: %04x %04x\n", go->interrupt_value, go->interrupt_data); -#endif } wake_up(&go->interrupt_waitq); @@ -801,8 +787,7 @@ static int go7007_usb_read_interrupt(struct go7007 *go) r = usb_submit_urb(usb->intr_urb, GFP_KERNEL); if (r < 0) { - printk(KERN_ERR - "go7007-usb: unable to submit interrupt urb: %d\n", r); + pr_err("unable to submit interrupt urb: %d\n", r); return r; } return 0; @@ -818,18 +803,17 @@ static void go7007_usb_read_video_pipe_complete(struct urb *urb) return; } if (status) { - printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", - status); + pr_err("error in video pipe: %d\n", status); return; } if (urb->actual_length != urb->transfer_buffer_length) { - printk(KERN_ERR "go7007-usb: short read in video pipe!\n"); + pr_err("short read in video pipe!\n"); return; } go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length); r = usb_submit_urb(urb, GFP_ATOMIC); if (r < 0) - printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", r); + pr_err("error in video pipe: %d\n", r); } static void go7007_usb_read_audio_pipe_complete(struct urb *urb) @@ -840,19 +824,19 @@ static void go7007_usb_read_audio_pipe_complete(struct urb *urb) if (!vb2_is_streaming(&go->vidq)) return; if (status) { - printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", + pr_err("error in audio pipe: %d\n", status); return; } if (urb->actual_length != urb->transfer_buffer_length) { - printk(KERN_ERR "go7007-usb: short read in audio pipe!\n"); + pr_err("short read in audio pipe!\n"); return; } if (go->audio_deliver != NULL) go->audio_deliver(go, urb->transfer_buffer, urb->actual_length); r = usb_submit_urb(urb, GFP_ATOMIC); if (r < 0) - printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", r); + pr_err("error in audio pipe: %d\n", r); } static int go7007_usb_stream_start(struct go7007 *go) @@ -863,8 +847,7 @@ static int go7007_usb_stream_start(struct go7007 *go) for (i = 0; i < 8; ++i) { r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL); if (r < 0) { - printk(KERN_ERR "go7007-usb: error submitting video " - "urb %d: %d\n", i, r); + pr_err("error submitting video urb %d: %d\n", i, r); goto video_submit_failed; } } @@ -874,8 +857,7 @@ static int go7007_usb_stream_start(struct go7007 *go) for (i = 0; i < 8; ++i) { r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL); if (r < 0) { - printk(KERN_ERR "go7007-usb: error submitting audio " - "urb %d: %d\n", i, r); + pr_err("error submitting audio urb %d: %d\n", i, r); goto audio_submit_failed; } } @@ -911,9 +893,7 @@ static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len) int transferred, pipe; int timeout = 500; -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG "go7007-usb: DownloadBuffer sending %d bytes\n", len); -#endif + pr_debug("DownloadBuffer sending %d bytes\n", len); if (usb->board->flags & GO7007_USB_EZUSB) pipe = usb_sndbulkpipe(usb->usbdev, 2); @@ -999,9 +979,8 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, !(msgs[i].flags & I2C_M_RD) && (msgs[i + 1].flags & I2C_M_RD)) { #ifdef GO7007_I2C_DEBUG - printk(KERN_DEBUG "go7007-usb: i2c write/read %d/%d " - "bytes on %02x\n", msgs[i].len, - msgs[i + 1].len, msgs[i].addr); + pr_debug("i2c write/read %d/%d bytes on %02x\n", + msgs[i].len, msgs[i + 1].len, msgs[i].addr); #endif buf[0] = 0x01; buf[1] = msgs[i].len + 1; @@ -1011,9 +990,8 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, buf[buf_len++] = msgs[++i].len; } else if (msgs[i].flags & I2C_M_RD) { #ifdef GO7007_I2C_DEBUG - printk(KERN_DEBUG "go7007-usb: i2c read %d " - "bytes on %02x\n", msgs[i].len, - msgs[i].addr); + pr_debug("i2c read %d bytes on %02x\n", + msgs[i].len, msgs[i].addr); #endif buf[0] = 0x01; buf[1] = 1; @@ -1022,9 +1000,8 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, buf_len = 4; } else { #ifdef GO7007_I2C_DEBUG - printk(KERN_DEBUG "go7007-usb: i2c write %d " - "bytes on %02x\n", msgs[i].len, - msgs[i].addr); + pr_debug("i2c write %d bytes on %02x\n", + msgs[i].len, msgs[i].addr); #endif buf[0] = 0x00; buf[1] = msgs[i].len + 1; @@ -1082,7 +1059,7 @@ static int go7007_usb_probe(struct usb_interface *intf, char *name; int video_pipe, i, v_urb_len; - printk(KERN_DEBUG "go7007-usb: probing new GO7007 USB board\n"); + pr_debug("probing new GO7007 USB board\n"); switch (id->driver_info) { case GO7007_BOARDID_MATRIX_II: @@ -1122,14 +1099,13 @@ static int go7007_usb_probe(struct usb_interface *intf, board = &board_px_tv402u; break; case GO7007_BOARDID_LIFEVIEW_LR192: - printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra " - "is not supported. Sorry!\n"); + pr_err("The Lifeview TV Walker Ultra is not supported. Sorry!\n"); return -ENODEV; name = "Lifeview TV Walker Ultra"; board = &board_lifeview_lr192; break; case GO7007_BOARDID_SENSORAY_2250: - printk(KERN_INFO "Sensoray 2250 found\n"); + pr_info("Sensoray 2250 found\n"); name = "Sensoray 2250/2251"; board = &board_sensoray_2250; break; @@ -1138,7 +1114,7 @@ static int go7007_usb_probe(struct usb_interface *intf, board = &board_ads_usbav_709; break; default: - printk(KERN_ERR "go7007-usb: unknown board ID %d!\n", + pr_err("unknown board ID %d!\n", (unsigned int)id->driver_info); return -ENODEV; } @@ -1197,8 +1173,7 @@ static int go7007_usb_probe(struct usb_interface *intf, go->i2c_adapter.dev.parent = go->dev; i2c_set_adapdata(&go->i2c_adapter, go); if (i2c_add_adapter(&go->i2c_adapter) < 0) { - printk(KERN_ERR - "go7007-usb: error: i2c_add_adapter failed\n"); + pr_err("error: i2c_add_adapter failed\n"); goto allocfail; } go->i2c_adapter_online = 1; @@ -1248,8 +1223,9 @@ static int go7007_usb_probe(struct usb_interface *intf, /* Probe the tuner model on the TV402U */ if (go->board_id == GO7007_BOARDID_PX_TV402U) { /* Board strapping indicates tuner model */ - if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3, 1) < 0) { - printk(KERN_ERR "go7007-usb: GPIO read failed!\n"); + if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3, + 1) < 0) { + pr_err("GPIO read failed!\n"); goto allocfail; } switch (go->usb_buf[0] >> 6) { @@ -1273,15 +1249,14 @@ static int go7007_usb_probe(struct usb_interface *intf, sizeof(go->name)); break; default: - printk(KERN_DEBUG "go7007-usb: unable to detect " - "tuner type!\n"); + pr_debug("unable to detect tuner type!\n"); break; } /* Configure tuner mode selection inputs connected * to the EZ-USB GPIO output pins */ if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0, NULL, 0, 0) < 0) { - printk(KERN_ERR "go7007-usb: GPIO write failed!\n"); + pr_err("GPIO write failed!\n"); goto allocfail; } } @@ -1290,11 +1265,7 @@ static int go7007_usb_probe(struct usb_interface *intf, * a USB1.1 port. There will be silent corruption of the stream. */ if ((board->flags & GO7007_USB_EZUSB) && usbdev->speed != USB_SPEED_HIGH) - printk(KERN_ERR "go7007-usb: *** WARNING *** This device " - "must be connected to a USB 2.0 port! " - "Attempting to capture video through a USB 1.1 " - "port will result in stream corruption, even " - "at low bitrates!\n"); + pr_err("*** WARNING *** This device must be connected to a USB 2.0 port! Attempting to capture video through a USB 1.1 port will result in stream corruption, even at low bitrates!\n"); /* Allocate the URBs and buffers for receiving the video stream */ if (board->flags & GO7007_USB_EZUSB) { diff --git a/drivers/staging/media/lirc/lirc_bt829.c b/drivers/staging/media/lirc/lirc_bt829.c index fa31ee7dd6a9..fbbdce4c119f 100644 --- a/drivers/staging/media/lirc/lirc_bt829.c +++ b/drivers/staging/media/lirc/lirc_bt829.c @@ -132,7 +132,7 @@ int init_module(void) atir_driver.minor = -1; atir_driver.code_length = 8; atir_driver.sample_rate = 10; - atir_driver.data = 0; + atir_driver.data = NULL; atir_driver.add_to_buf = atir_add_to_buf; atir_driver.set_use_inc = atir_set_use_inc; atir_driver.set_use_dec = atir_set_use_dec; @@ -159,7 +159,7 @@ void cleanup_module(void) static int atir_init_start(void) { pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400); - if (pci_addr_lin == 0) { + if (!pci_addr_lin) { pr_info("pci mem must be mapped\n"); return 0; } diff --git a/drivers/staging/mt29f_spinand/Kconfig b/drivers/staging/mt29f_spinand/Kconfig new file mode 100644 index 000000000000..403174817be7 --- /dev/null +++ b/drivers/staging/mt29f_spinand/Kconfig @@ -0,0 +1,16 @@ +config MTD_SPINAND_MT29F + tristate "SPINAND Device Support for Micron" + depends on MTD_NAND && SPI + help + This enables support for accessing Micron SPI NAND flash + devices. + If you have Micron SPI NAND chip say yes. + + If unsure, say no here. + +config MTD_SPINAND_ONDIEECC + bool "Use SPINAND internal ECC" + depends on MTD_SPINAND_MT29F + help + Internel ECC. + Enables Hardware ECC support for Micron SPI NAND. diff --git a/drivers/staging/mt29f_spinand/Makefile b/drivers/staging/mt29f_spinand/Makefile new file mode 100644 index 000000000000..e47af0f7fda9 --- /dev/null +++ b/drivers/staging/mt29f_spinand/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand.o diff --git a/drivers/staging/mt29f_spinand/TODO b/drivers/staging/mt29f_spinand/TODO new file mode 100644 index 000000000000..a2209b72d371 --- /dev/null +++ b/drivers/staging/mt29f_spinand/TODO @@ -0,0 +1,13 @@ +TODO: + - Tested on XLP platform, needs to be tested on other platforms. + - Checkpatch.pl cleanups + - Sparce fixes. + - Clean up coding style to meet kernel standard. + +Please send patches +To: +Kamlakant Patel <kamlakant.patel@broadcom.com> +Cc: +Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Mona Anonuevo <manonuevo@micron.com> +linux-mtd@lists.infradead.org diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c new file mode 100644 index 000000000000..51dbc13e757f --- /dev/null +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c @@ -0,0 +1,947 @@ +/* + * Copyright (c) 2003-2013 Broadcom Corporation + * + * Copyright (c) 2009-2010 Micron Technology, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand.h> +#include <linux/spi/spi.h> + +#include "mt29f_spinand.h" + +#define BUFSIZE (10 * 64 * 2048) +#define CACHE_BUF 2112 +/* + * OOB area specification layout: Total 32 available free bytes. + */ + +static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd) +{ + struct nand_chip *chip = (struct nand_chip *)mtd->priv; + struct spinand_info *info = (struct spinand_info *)chip->priv; + struct spinand_state *state = (struct spinand_state *)info->priv; + + return state; +} + +#ifdef CONFIG_MTD_SPINAND_ONDIEECC +static int enable_hw_ecc; +static int enable_read_hw_ecc; + +static struct nand_ecclayout spinand_oob_64 = { + .eccbytes = 24, + .eccpos = { + 1, 2, 3, 4, 5, 6, + 17, 18, 19, 20, 21, 22, + 33, 34, 35, 36, 37, 38, + 49, 50, 51, 52, 53, 54, }, + .oobavail = 32, + .oobfree = { + {.offset = 8, + .length = 8}, + {.offset = 24, + .length = 8}, + {.offset = 40, + .length = 8}, + {.offset = 56, + .length = 8}, + } +}; +#endif + +/* + * spinand_cmd - to process a command to send to the SPI Nand + * Description: + * Set up the command buffer to send to the SPI controller. + * The command buffer has to initialized to 0. + */ + +static int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd) +{ + struct spi_message message; + struct spi_transfer x[4]; + u8 dummy = 0xff; + + spi_message_init(&message); + memset(x, 0, sizeof(x)); + + x[0].len = 1; + x[0].tx_buf = &cmd->cmd; + spi_message_add_tail(&x[0], &message); + + if (cmd->n_addr) { + x[1].len = cmd->n_addr; + x[1].tx_buf = cmd->addr; + spi_message_add_tail(&x[1], &message); + } + + if (cmd->n_dummy) { + x[2].len = cmd->n_dummy; + x[2].tx_buf = &dummy; + spi_message_add_tail(&x[2], &message); + } + + if (cmd->n_tx) { + x[3].len = cmd->n_tx; + x[3].tx_buf = cmd->tx_buf; + spi_message_add_tail(&x[3], &message); + } + + if (cmd->n_rx) { + x[3].len = cmd->n_rx; + x[3].rx_buf = cmd->rx_buf; + spi_message_add_tail(&x[3], &message); + } + + return spi_sync(spi, &message); +} + +/* + * spinand_read_id- Read SPI Nand ID + * Description: + * Read ID: read two ID bytes from the SPI Nand device + */ +static int spinand_read_id(struct spi_device *spi_nand, u8 *id) +{ + int retval; + u8 nand_id[3]; + struct spinand_cmd cmd = {0}; + + cmd.cmd = CMD_READ_ID; + cmd.n_rx = 3; + cmd.rx_buf = &nand_id[0]; + + retval = spinand_cmd(spi_nand, &cmd); + if (retval < 0) { + dev_err(&spi_nand->dev, "error %d reading id\n", retval); + return retval; + } + id[0] = nand_id[1]; + id[1] = nand_id[2]; + return retval; +} + +/* + * spinand_read_status- send command 0xf to the SPI Nand status register + * Description: + * After read, write, or erase, the Nand device is expected to set the + * busy status. + * This function is to allow reading the status of the command: read, + * write, and erase. + * Once the status turns to be ready, the other status bits also are + * valid status bits. + */ +static int spinand_read_status(struct spi_device *spi_nand, uint8_t *status) +{ + struct spinand_cmd cmd = {0}; + int ret; + + cmd.cmd = CMD_READ_REG; + cmd.n_addr = 1; + cmd.addr[0] = REG_STATUS; + cmd.n_rx = 1; + cmd.rx_buf = status; + + ret = spinand_cmd(spi_nand, &cmd); + if (ret < 0) + dev_err(&spi_nand->dev, "err: %d read status register\n", ret); + + return ret; +} + +#define MAX_WAIT_JIFFIES (40 * HZ) +static int wait_till_ready(struct spi_device *spi_nand) +{ + unsigned long deadline; + int retval; + u8 stat = 0; + + deadline = jiffies + MAX_WAIT_JIFFIES; + do { + retval = spinand_read_status(spi_nand, &stat); + if (retval < 0) + return -1; + else if (!(stat & 0x1)) + break; + + cond_resched(); + } while (!time_after_eq(jiffies, deadline)); + + if ((stat & 0x1) == 0) + return 0; + + return -1; +} +/** + * spinand_get_otp- send command 0xf to read the SPI Nand OTP register + * Description: + * There is one bit( bit 0x10 ) to set or to clear the internal ECC. + * Enable chip internal ECC, set the bit to 1 + * Disable chip internal ECC, clear the bit to 0 + */ +static int spinand_get_otp(struct spi_device *spi_nand, u8 *otp) +{ + struct spinand_cmd cmd = {0}; + int retval; + + cmd.cmd = CMD_READ_REG; + cmd.n_addr = 1; + cmd.addr[0] = REG_OTP; + cmd.n_rx = 1; + cmd.rx_buf = otp; + + retval = spinand_cmd(spi_nand, &cmd); + if (retval < 0) + dev_err(&spi_nand->dev, "error %d get otp\n", retval); + return retval; +} + +/** + * spinand_set_otp- send command 0x1f to write the SPI Nand OTP register + * Description: + * There is one bit( bit 0x10 ) to set or to clear the internal ECC. + * Enable chip internal ECC, set the bit to 1 + * Disable chip internal ECC, clear the bit to 0 + */ +static int spinand_set_otp(struct spi_device *spi_nand, u8 *otp) +{ + int retval; + struct spinand_cmd cmd = {0}; + + cmd.cmd = CMD_WRITE_REG, + cmd.n_addr = 1, + cmd.addr[0] = REG_OTP, + cmd.n_tx = 1, + cmd.tx_buf = otp, + + retval = spinand_cmd(spi_nand, &cmd); + if (retval < 0) + dev_err(&spi_nand->dev, "error %d set otp\n", retval); + + return retval; +} + +#ifdef CONFIG_MTD_SPINAND_ONDIEECC +/** + * spinand_enable_ecc- send command 0x1f to write the SPI Nand OTP register + * Description: + * There is one bit( bit 0x10 ) to set or to clear the internal ECC. + * Enable chip internal ECC, set the bit to 1 + * Disable chip internal ECC, clear the bit to 0 + */ +static int spinand_enable_ecc(struct spi_device *spi_nand) +{ + int retval; + u8 otp = 0; + + retval = spinand_get_otp(spi_nand, &otp); + if (retval < 0) + return retval; + + if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) { + return 0; + } else { + otp |= OTP_ECC_MASK; + retval = spinand_set_otp(spi_nand, &otp); + if (retval < 0) + return retval; + return spinand_get_otp(spi_nand, &otp); + } +} +#endif + +static int spinand_disable_ecc(struct spi_device *spi_nand) +{ + int retval; + u8 otp = 0; + + retval = spinand_get_otp(spi_nand, &otp); + if (retval < 0) + return retval; + + if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) { + otp &= ~OTP_ECC_MASK; + retval = spinand_set_otp(spi_nand, &otp); + if (retval < 0) + return retval; + return spinand_get_otp(spi_nand, &otp); + } else + return 0; +} + +/** + * spinand_write_enable- send command 0x06 to enable write or erase the + * Nand cells + * Description: + * Before write and erase the Nand cells, the write enable has to be set. + * After the write or erase, the write enable bit is automatically + * cleared (status register bit 2) + * Set the bit 2 of the status register has the same effect + */ +static int spinand_write_enable(struct spi_device *spi_nand) +{ + struct spinand_cmd cmd = {0}; + + cmd.cmd = CMD_WR_ENABLE; + return spinand_cmd(spi_nand, &cmd); +} + +static int spinand_read_page_to_cache(struct spi_device *spi_nand, u16 page_id) +{ + struct spinand_cmd cmd = {0}; + u16 row; + + row = page_id; + cmd.cmd = CMD_READ; + cmd.n_addr = 3; + cmd.addr[1] = (u8)((row & 0xff00) >> 8); + cmd.addr[2] = (u8)(row & 0x00ff); + + return spinand_cmd(spi_nand, &cmd); +} + +/* + * spinand_read_from_cache- send command 0x03 to read out the data from the + * cache register(2112 bytes max) + * Description: + * The read can specify 1 to 2112 bytes of data read at the corresponding + * locations. + * No tRd delay. + */ +static int spinand_read_from_cache(struct spi_device *spi_nand, u16 page_id, + u16 byte_id, u16 len, u8 *rbuf) +{ + struct spinand_cmd cmd = {0}; + u16 column; + + column = byte_id; + cmd.cmd = CMD_READ_RDM; + cmd.n_addr = 3; + cmd.addr[0] = (u8)((column & 0xff00) >> 8); + cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4); + cmd.addr[1] = (u8)(column & 0x00ff); + cmd.addr[2] = (u8)(0xff); + cmd.n_dummy = 0; + cmd.n_rx = len; + cmd.rx_buf = rbuf; + + return spinand_cmd(spi_nand, &cmd); +} + +/* + * spinand_read_page-to read a page with: + * @page_id: the physical page number + * @offset: the location from 0 to 2111 + * @len: number of bytes to read + * @rbuf: read buffer to hold @len bytes + * + * Description: + * The read includes two commands to the Nand: 0x13 and 0x03 commands + * Poll to read status to wait for tRD time. + */ +static int spinand_read_page(struct spi_device *spi_nand, u16 page_id, + u16 offset, u16 len, u8 *rbuf) +{ + int ret; + u8 status = 0; + +#ifdef CONFIG_MTD_SPINAND_ONDIEECC + if (enable_read_hw_ecc) { + if (spinand_enable_ecc(spi_nand) < 0) + dev_err(&spi_nand->dev, "enable HW ECC failed!"); + } +#endif + ret = spinand_read_page_to_cache(spi_nand, page_id); + if (ret < 0) + return ret; + + if (wait_till_ready(spi_nand)) + dev_err(&spi_nand->dev, "WAIT timedout!!!\n"); + + while (1) { + ret = spinand_read_status(spi_nand, &status); + if (ret < 0) { + dev_err(&spi_nand->dev, + "err %d read status register\n", ret); + return ret; + } + + if ((status & STATUS_OIP_MASK) == STATUS_READY) { + if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) { + dev_err(&spi_nand->dev, "ecc error, page=%d\n", + page_id); + return 0; + } + break; + } + } + + ret = spinand_read_from_cache(spi_nand, page_id, offset, len, rbuf); + if (ret < 0) { + dev_err(&spi_nand->dev, "read from cache failed!!\n"); + return ret; + } + +#ifdef CONFIG_MTD_SPINAND_ONDIEECC + if (enable_read_hw_ecc) { + ret = spinand_disable_ecc(spi_nand); + if (ret < 0) { + dev_err(&spi_nand->dev, "disable ecc failed!!\n"); + return ret; + } + enable_read_hw_ecc = 0; + } +#endif + return ret; +} + +/* + * spinand_program_data_to_cache--to write a page to cache with: + * @byte_id: the location to write to the cache + * @len: number of bytes to write + * @rbuf: read buffer to hold @len bytes + * + * Description: + * The write command used here is 0x84--indicating that the cache is + * not cleared first. + * Since it is writing the data to cache, there is no tPROG time. + */ +static int spinand_program_data_to_cache(struct spi_device *spi_nand, + u16 page_id, u16 byte_id, u16 len, u8 *wbuf) +{ + struct spinand_cmd cmd = {0}; + u16 column; + + column = byte_id; + cmd.cmd = CMD_PROG_PAGE_CLRCACHE; + cmd.n_addr = 2; + cmd.addr[0] = (u8)((column & 0xff00) >> 8); + cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4); + cmd.addr[1] = (u8)(column & 0x00ff); + cmd.n_tx = len; + cmd.tx_buf = wbuf; + + return spinand_cmd(spi_nand, &cmd); +} + +/** + * spinand_program_execute--to write a page from cache to the Nand array with + * @page_id: the physical page location to write the page. + * + * Description: + * The write command used here is 0x10--indicating the cache is writing to + * the Nand array. + * Need to wait for tPROG time to finish the transaction. + */ +static int spinand_program_execute(struct spi_device *spi_nand, u16 page_id) +{ + struct spinand_cmd cmd = {0}; + u16 row; + + row = page_id; + cmd.cmd = CMD_PROG_PAGE_EXC; + cmd.n_addr = 3; + cmd.addr[1] = (u8)((row & 0xff00) >> 8); + cmd.addr[2] = (u8)(row & 0x00ff); + + return spinand_cmd(spi_nand, &cmd); +} + +/** + * spinand_program_page--to write a page with: + * @page_id: the physical page location to write the page. + * @offset: the location from the cache starting from 0 to 2111 + * @len: the number of bytes to write + * @wbuf: the buffer to hold the number of bytes + * + * Description: + * The commands used here are 0x06, 0x84, and 0x10--indicating that + * the write enable is first sent, the write cache command, and the + * write execute command. + * Poll to wait for the tPROG time to finish the transaction. + */ +static int spinand_program_page(struct spi_device *spi_nand, + u16 page_id, u16 offset, u16 len, u8 *buf) +{ + int retval; + u8 status = 0; + uint8_t *wbuf; +#ifdef CONFIG_MTD_SPINAND_ONDIEECC + unsigned int i, j; + + enable_read_hw_ecc = 0; + wbuf = devm_kzalloc(&spi_nand->dev, CACHE_BUF, GFP_KERNEL); + spinand_read_page(spi_nand, page_id, 0, CACHE_BUF, wbuf); + + for (i = offset, j = 0; i < len; i++, j++) + wbuf[i] &= buf[j]; + + if (enable_hw_ecc) { + retval = spinand_enable_ecc(spi_nand); + if (retval < 0) { + dev_err(&spi_nand->dev, "enable ecc failed!!\n"); + return retval; + } + } +#else + wbuf = buf; +#endif + retval = spinand_write_enable(spi_nand); + if (retval < 0) { + dev_err(&spi_nand->dev, "write enable failed!!\n"); + return retval; + } + if (wait_till_ready(spi_nand)) + dev_err(&spi_nand->dev, "wait timedout!!!\n"); + + retval = spinand_program_data_to_cache(spi_nand, page_id, + offset, len, wbuf); + if (retval < 0) + return retval; + retval = spinand_program_execute(spi_nand, page_id); + if (retval < 0) + return retval; + while (1) { + retval = spinand_read_status(spi_nand, &status); + if (retval < 0) { + dev_err(&spi_nand->dev, + "error %d reading status register\n", + retval); + return retval; + } + + if ((status & STATUS_OIP_MASK) == STATUS_READY) { + if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL) { + dev_err(&spi_nand->dev, + "program error, page %d\n", page_id); + return -1; + } else + break; + } + } +#ifdef CONFIG_MTD_SPINAND_ONDIEECC + if (enable_hw_ecc) { + retval = spinand_disable_ecc(spi_nand); + if (retval < 0) { + dev_err(&spi_nand->dev, "disable ecc failed!!\n"); + return retval; + } + enable_hw_ecc = 0; + } +#endif + + return 0; +} + +/** + * spinand_erase_block_erase--to erase a page with: + * @block_id: the physical block location to erase. + * + * Description: + * The command used here is 0xd8--indicating an erase command to erase + * one block--64 pages + * Need to wait for tERS. + */ +static int spinand_erase_block_erase(struct spi_device *spi_nand, u16 block_id) +{ + struct spinand_cmd cmd = {0}; + u16 row; + + row = block_id; + cmd.cmd = CMD_ERASE_BLK; + cmd.n_addr = 3; + cmd.addr[1] = (u8)((row & 0xff00) >> 8); + cmd.addr[2] = (u8)(row & 0x00ff); + + return spinand_cmd(spi_nand, &cmd); +} + +/** + * spinand_erase_block--to erase a page with: + * @block_id: the physical block location to erase. + * + * Description: + * The commands used here are 0x06 and 0xd8--indicating an erase + * command to erase one block--64 pages + * It will first to enable the write enable bit (0x06 command), + * and then send the 0xd8 erase command + * Poll to wait for the tERS time to complete the tranaction. + */ +static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id) +{ + int retval; + u8 status = 0; + + retval = spinand_write_enable(spi_nand); + if (wait_till_ready(spi_nand)) + dev_err(&spi_nand->dev, "wait timedout!!!\n"); + + retval = spinand_erase_block_erase(spi_nand, block_id); + while (1) { + retval = spinand_read_status(spi_nand, &status); + if (retval < 0) { + dev_err(&spi_nand->dev, + "error %d reading status register\n", + (int) retval); + return retval; + } + + if ((status & STATUS_OIP_MASK) == STATUS_READY) { + if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL) { + dev_err(&spi_nand->dev, + "erase error, block %d\n", block_id); + return -1; + } else + break; + } + } + return 0; +} + +#ifdef CONFIG_MTD_SPINAND_ONDIEECC +static int spinand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required) +{ + const uint8_t *p = buf; + int eccsize = chip->ecc.size; + int eccsteps = chip->ecc.steps; + + enable_hw_ecc = 1; + chip->write_buf(mtd, p, eccsize * eccsteps); + return 0; +} + +static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + u8 retval, status; + uint8_t *p = buf; + int eccsize = chip->ecc.size; + int eccsteps = chip->ecc.steps; + struct spinand_info *info = (struct spinand_info *)chip->priv; + + enable_read_hw_ecc = 1; + + chip->read_buf(mtd, p, eccsize * eccsteps); + if (oob_required) + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + while (1) { + retval = spinand_read_status(info->spi, &status); + if ((status & STATUS_OIP_MASK) == STATUS_READY) { + if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) { + pr_info("spinand: ECC error\n"); + mtd->ecc_stats.failed++; + } else if ((status & STATUS_ECC_MASK) == + STATUS_ECC_1BIT_CORRECTED) + mtd->ecc_stats.corrected++; + break; + } + } + return 0; + +} +#endif + +static void spinand_select_chip(struct mtd_info *mtd, int dev) +{ +} + +static uint8_t spinand_read_byte(struct mtd_info *mtd) +{ + struct spinand_state *state = mtd_to_state(mtd); + u8 data; + + data = state->buf[state->buf_ptr]; + state->buf_ptr++; + return data; +} + + +static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip) +{ + struct spinand_info *info = (struct spinand_info *)chip->priv; + + unsigned long timeo = jiffies; + int retval, state = chip->state; + u8 status; + + if (state == FL_ERASING) + timeo += (HZ * 400) / 1000; + else + timeo += (HZ * 20) / 1000; + + while (time_before(jiffies, timeo)) { + retval = spinand_read_status(info->spi, &status); + if ((status & STATUS_OIP_MASK) == STATUS_READY) + return 0; + + cond_resched(); + } + return 0; +} + +static void spinand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + + struct spinand_state *state = mtd_to_state(mtd); + memcpy(state->buf + state->buf_ptr, buf, len); + state->buf_ptr += len; +} + +static void spinand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct spinand_state *state = mtd_to_state(mtd); + memcpy(buf, state->buf + state->buf_ptr, len); + state->buf_ptr += len; +} + +/* + * spinand_reset- send RESET command "0xff" to the Nand device. + */ +static void spinand_reset(struct spi_device *spi_nand) +{ + struct spinand_cmd cmd = {0}; + + cmd.cmd = CMD_RESET; + + if (spinand_cmd(spi_nand, &cmd) < 0) + pr_info("spinand reset failed!\n"); + + /* elapse 1ms before issuing any other command */ + udelay(1000); + + if (wait_till_ready(spi_nand)) + dev_err(&spi_nand->dev, "wait timedout!\n"); +} + +static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command, + int column, int page) +{ + struct nand_chip *chip = (struct nand_chip *)mtd->priv; + struct spinand_info *info = (struct spinand_info *)chip->priv; + struct spinand_state *state = (struct spinand_state *)info->priv; + + switch (command) { + /* + * READ0 - read in first 0x800 bytes + */ + case NAND_CMD_READ1: + case NAND_CMD_READ0: + state->buf_ptr = 0; + spinand_read_page(info->spi, page, 0x0, 0x840, state->buf); + break; + /* READOOB reads only the OOB because no ECC is performed. */ + case NAND_CMD_READOOB: + state->buf_ptr = 0; + spinand_read_page(info->spi, page, 0x800, 0x40, state->buf); + break; + case NAND_CMD_RNDOUT: + state->buf_ptr = column; + break; + case NAND_CMD_READID: + state->buf_ptr = 0; + spinand_read_id(info->spi, (u8 *)state->buf); + break; + case NAND_CMD_PARAM: + state->buf_ptr = 0; + break; + /* ERASE1 stores the block and page address */ + case NAND_CMD_ERASE1: + spinand_erase_block(info->spi, page); + break; + /* ERASE2 uses the block and page address from ERASE1 */ + case NAND_CMD_ERASE2: + break; + /* SEQIN sets up the addr buffer and all registers except the length */ + case NAND_CMD_SEQIN: + state->col = column; + state->row = page; + state->buf_ptr = 0; + break; + /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ + case NAND_CMD_PAGEPROG: + spinand_program_page(info->spi, state->row, state->col, + state->buf_ptr, state->buf); + break; + case NAND_CMD_STATUS: + spinand_get_otp(info->spi, state->buf); + if (!(state->buf[0] & 0x80)) + state->buf[0] = 0x80; + state->buf_ptr = 0; + break; + /* RESET command */ + case NAND_CMD_RESET: + if (wait_till_ready(info->spi)) + dev_err(&info->spi->dev, "WAIT timedout!!!\n"); + /* a minimum of 250us must elapse before issuing RESET cmd*/ + udelay(250); + spinand_reset(info->spi); + break; + default: + dev_err(&mtd->dev, "Unknown CMD: 0x%x\n", command); + } +} + +/** + * spinand_lock_block- send write register 0x1f command to the Nand device + * + * Description: + * After power up, all the Nand blocks are locked. This function allows + * one to unlock the blocks, and so it can be written or erased. + */ +static int spinand_lock_block(struct spi_device *spi_nand, u8 lock) +{ + struct spinand_cmd cmd = {0}; + int ret; + u8 otp = 0; + + ret = spinand_get_otp(spi_nand, &otp); + + cmd.cmd = CMD_WRITE_REG; + cmd.n_addr = 1; + cmd.addr[0] = REG_BLOCK_LOCK; + cmd.n_tx = 1; + cmd.tx_buf = &lock; + + ret = spinand_cmd(spi_nand, &cmd); + if (ret < 0) + dev_err(&spi_nand->dev, "error %d lock block\n", ret); + + return ret; +} +/* + * spinand_probe - [spinand Interface] + * @spi_nand: registered device driver. + * + * Description: + * To set up the device driver parameters to make the device available. + */ +static int spinand_probe(struct spi_device *spi_nand) +{ + struct mtd_info *mtd; + struct nand_chip *chip; + struct spinand_info *info; + struct spinand_state *state; + struct mtd_part_parser_data ppdata; + + info = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->spi = spi_nand; + + spinand_lock_block(spi_nand, BL_ALL_UNLOCKED); + + state = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_state), + GFP_KERNEL); + if (!state) + return -ENOMEM; + + info->priv = state; + state->buf_ptr = 0; + state->buf = devm_kzalloc(&spi_nand->dev, BUFSIZE, GFP_KERNEL); + if (!state->buf) + return -ENOMEM; + + chip = devm_kzalloc(&spi_nand->dev, sizeof(struct nand_chip), + GFP_KERNEL); + if (!chip) + return -ENOMEM; + +#ifdef CONFIG_MTD_SPINAND_ONDIEECC + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = 0x200; + chip->ecc.bytes = 0x6; + chip->ecc.steps = 0x4; + + chip->ecc.strength = 1; + chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; + chip->ecc.layout = &spinand_oob_64; + chip->ecc.read_page = spinand_read_page_hwecc; + chip->ecc.write_page = spinand_write_page_hwecc; +#else + chip->ecc.mode = NAND_ECC_SOFT; + if (spinand_disable_ecc(spi_nand) < 0) + pr_info("%s: disable ecc failed!\n", __func__); +#endif + + chip->priv = info; + chip->read_buf = spinand_read_buf; + chip->write_buf = spinand_write_buf; + chip->read_byte = spinand_read_byte; + chip->cmdfunc = spinand_cmdfunc; + chip->waitfunc = spinand_wait; + chip->options |= NAND_CACHEPRG; + chip->select_chip = spinand_select_chip; + + mtd = devm_kzalloc(&spi_nand->dev, sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd) + return -ENOMEM; + + dev_set_drvdata(&spi_nand->dev, mtd); + + mtd->priv = chip; + mtd->name = dev_name(&spi_nand->dev); + mtd->owner = THIS_MODULE; + mtd->oobsize = 64; + + if (nand_scan(mtd, 1)) + return -ENXIO; + + ppdata.of_node = spi_nand->dev.of_node; + return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); +} + +/* + * spinand_remove: Remove the device driver + * @spi: the spi device. + * + * Description: + * To remove the device driver parameters and free up allocated memories. + */ +static int spinand_remove(struct spi_device *spi) +{ + mtd_device_unregister(dev_get_drvdata(&spi->dev)); + + return 0; +} + +static const struct of_device_id spinand_dt[] = { + { .compatible = "spinand,mt29f", }, +}; + +/* + * Device name structure description + */ +static struct spi_driver spinand_driver = { + .driver = { + .name = "mt29f", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + .of_match_table = spinand_dt, + }, + .probe = spinand_probe, + .remove = spinand_remove, +}; + +module_spi_driver(spinand_driver); + +MODULE_DESCRIPTION("SPI NAND driver for Micron"); +MODULE_AUTHOR("Henry Pan <hspan@micron.com>, Kamlakant Patel <kamlakant.patel@broadcom.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.h b/drivers/staging/mt29f_spinand/mt29f_spinand.h new file mode 100644 index 000000000000..7f2c24dc51b4 --- /dev/null +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.h @@ -0,0 +1,107 @@ +/*- + * Copyright 2013 Broadcom Corporation + * + * Copyright (c) 2009-2010 Micron Technology, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Henry Pan <hspan@micron.com> + * + * based on nand.h + */ +#ifndef __LINUX_MTD_SPI_NAND_H +#define __LINUX_MTD_SPI_NAND_H + +#include <linux/wait.h> +#include <linux/spinlock.h> +#include <linux/mtd/mtd.h> + +/* cmd */ +#define CMD_READ 0x13 +#define CMD_READ_RDM 0x03 +#define CMD_PROG_PAGE_CLRCACHE 0x02 +#define CMD_PROG_PAGE 0x84 +#define CMD_PROG_PAGE_EXC 0x10 +#define CMD_ERASE_BLK 0xd8 +#define CMD_WR_ENABLE 0x06 +#define CMD_WR_DISABLE 0x04 +#define CMD_READ_ID 0x9f +#define CMD_RESET 0xff +#define CMD_READ_REG 0x0f +#define CMD_WRITE_REG 0x1f + +/* feature/ status reg */ +#define REG_BLOCK_LOCK 0xa0 +#define REG_OTP 0xb0 +#define REG_STATUS 0xc0/* timing */ + +/* status */ +#define STATUS_OIP_MASK 0x01 +#define STATUS_READY (0 << 0) +#define STATUS_BUSY (1 << 0) + +#define STATUS_E_FAIL_MASK 0x04 +#define STATUS_E_FAIL (1 << 2) + +#define STATUS_P_FAIL_MASK 0x08 +#define STATUS_P_FAIL (1 << 3) + +#define STATUS_ECC_MASK 0x30 +#define STATUS_ECC_1BIT_CORRECTED (1 << 4) +#define STATUS_ECC_ERROR (2 << 4) +#define STATUS_ECC_RESERVED (3 << 4) + +/*ECC enable defines*/ +#define OTP_ECC_MASK 0x10 +#define OTP_ECC_OFF 0 +#define OTP_ECC_ON 1 + +#define ECC_DISABLED +#define ECC_IN_NAND +#define ECC_SOFT + +/* block lock */ +#define BL_ALL_LOCKED 0x38 +#define BL_1_2_LOCKED 0x30 +#define BL_1_4_LOCKED 0x28 +#define BL_1_8_LOCKED 0x20 +#define BL_1_16_LOCKED 0x18 +#define BL_1_32_LOCKED 0x10 +#define BL_1_64_LOCKED 0x08 +#define BL_ALL_UNLOCKED 0 + +struct spinand_info { + struct nand_ecclayout *ecclayout; + struct spi_device *spi; + void *priv; +}; + +struct spinand_state { + uint32_t col; + uint32_t row; + int buf_ptr; + u8 *buf; +}; + +struct spinand_cmd { + u8 cmd; + u32 n_addr; /* Number of address */ + u8 addr[3]; /* Reg Offset */ + u32 n_dummy; /* Dummy use */ + u32 n_tx; /* Number of tx bytes */ + u8 *tx_buf; /* Tx buf */ + u32 n_rx; /* Number of rx bytes */ + u8 *rx_buf; /* Rx buf */ +}; + +extern int spinand_mtd(struct mtd_info *mtd); +extern void spinand_mtd_release(struct mtd_info *mtd); + +#endif /* __LINUX_MTD_SPI_NAND_H */ diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c index 46eabd0e426a..235d2b1ec593 100644 --- a/drivers/staging/netlogic/xlr_net.c +++ b/drivers/staging/netlogic/xlr_net.c @@ -44,8 +44,8 @@ #include <linux/platform_device.h> #include <asm/mipsregs.h> - -/* fmn.h - For FMN credit configuration and registering fmn_handler. +/* + * fmn.h - For FMN credit configuration and registering fmn_handler. * FMN is communication mechanism that allows processing agents within * XLR/XLS to communicate each other. */ @@ -90,7 +90,8 @@ static inline struct sk_buff *mac_get_skb_back_ptr(void *addr) { struct sk_buff **back_ptr; - /* this function should be used only for newly allocated packets. + /* + * this function should be used only for newly allocated packets. * It assumes the first cacheline is for the back pointer related * book keeping info. */ @@ -102,7 +103,8 @@ static inline void mac_put_skb_back_ptr(struct sk_buff *skb) { struct sk_buff **back_ptr = (struct sk_buff **)skb->data; - /* this function should be used only for newly allocated packets. + /* + * this function should be used only for newly allocated packets. * It assumes the first cacheline is for the back pointer related * book keeping info. */ @@ -500,8 +502,10 @@ static void xlr_config_fifo_spill_area(struct xlr_net_priv *priv) sizeof(u64)); } -/* Configure PDE to Round-Robin distribution of packets to the - * available cpu */ +/* + * Configure PDE to Round-Robin distribution of packets to the + * available cpu + */ static void xlr_config_pde(struct xlr_net_priv *priv) { int i = 0; @@ -528,8 +532,10 @@ static void xlr_config_pde(struct xlr_net_priv *priv) ((bkt_map >> 32) & 0xffffffff)); } -/* Setup the Message ring credits, bucket size and other - * common configuration */ +/* + * Setup the Message ring credits, bucket size and other + * common configuration + */ static void xlr_config_common(struct xlr_net_priv *priv) { struct xlr_fmn_info *gmac = priv->nd->gmac_fmn_info; @@ -545,8 +551,10 @@ static void xlr_config_common(struct xlr_net_priv *priv) bucket_size[i]); } - /* Setting non-core Credit counter register - * Distributing Gmac's credit to CPU's*/ + /* + * Setting non-core Credit counter register + * Distributing Gmac's credit to CPU's + */ for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) xlr_nae_wreg(priv->base_addr, @@ -593,7 +601,8 @@ static void xlr_config_translate_table(struct xlr_net_priv *priv) c1 = 3; c2 = 0; for (i = 0; i < 64; i++) { - /* On use_bkt set the b0, b1 are used, else + /* + * On use_bkt set the b0, b1 are used, else * the 4 classes are used, here implemented * a logic to distribute the packets to the * buckets equally or based on the class @@ -736,7 +745,8 @@ static int xlr_mii_read(struct mii_bus *bus, int phy_addr, int regnum) return ret; } -/* XLR ports are RGMII. XLS ports are SGMII mostly except the port0, +/* + * XLR ports are RGMII. XLS ports are SGMII mostly except the port0, * which can be configured either SGMII or RGMII, considered SGMII * by default, if board setup to RGMII the port_type need to set * accordingly.Serdes and PCS layer need to configured for SGMII diff --git a/drivers/staging/netlogic/xlr_net.h b/drivers/staging/netlogic/xlr_net.h index f91d27e9d7c4..cea796633711 100644 --- a/drivers/staging/netlogic/xlr_net.h +++ b/drivers/staging/netlogic/xlr_net.h @@ -1096,4 +1096,4 @@ struct xlr_net_priv { u64 *class_3_spill; }; -extern void xlr_set_gmac_speed(struct xlr_net_priv *priv); +void xlr_set_gmac_speed(struct xlr_net_priv *priv); diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 5a5c6397e740..3066ee2e753b 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -802,7 +802,7 @@ static int tegra_nvec_probe(struct platform_device *pdev) unmute_speakers[] = { NVEC_OEM0, 0x10, 0x59, 0x95 }, enable_event[7] = { NVEC_SYS, CNF_EVENT_REPORTING, true }; - if(!pdev->dev.of_node) { + if (!pdev->dev.of_node) { dev_err(&pdev->dev, "must be instantiated using device tree\n"); return -ENODEV; } diff --git a/drivers/staging/octeon-usb/Makefile b/drivers/staging/octeon-usb/Makefile index 89df1ad8be30..5588be395f2a 100644 --- a/drivers/staging/octeon-usb/Makefile +++ b/drivers/staging/octeon-usb/Makefile @@ -1,3 +1 @@ -obj-${CONFIG_OCTEON_USB} := octeon-usb.o -octeon-usb-y := octeon-hcd.o -octeon-usb-y += cvmx-usb.o +obj-${CONFIG_OCTEON_USB} := octeon-hcd.o diff --git a/drivers/staging/octeon-usb/cvmx-usb.c b/drivers/staging/octeon-usb/cvmx-usb.c deleted file mode 100644 index 45dfe94199ae..000000000000 --- a/drivers/staging/octeon-usb/cvmx-usb.c +++ /dev/null @@ -1,3158 +0,0 @@ -/***********************license start*************** - * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights - * reserved. - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - - * * Neither the name of Cavium Networks nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written - * permission. - - * This Software, including technical data, may be subject to U.S. export control - * laws, including the U.S. Export Administration Act and its associated - * regulations, and may be subject to export or import regulations in other - * countries. - - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR - * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO - * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR - * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM - * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, - * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF - * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR - * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR - * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. - ***********************license end**************************************/ - - -/** - * @file - * - * "cvmx-usb.c" defines a set of low level USB functions to help - * developers create Octeon USB drivers for various operating - * systems. These functions provide a generic API to the Octeon - * USB blocks, hiding the internal hardware specific - * operations. - */ -#include <linux/delay.h> -#include <asm/octeon/cvmx.h> -#include <asm/octeon/octeon.h> -#include <asm/octeon/cvmx-sysinfo.h> -#include "cvmx-usbnx-defs.h" -#include "cvmx-usbcx-defs.h" -#include "cvmx-usb.h" -#include <asm/octeon/cvmx-helper.h> -#include <asm/octeon/cvmx-helper-board.h> - -#define CVMX_PREFETCH0(address) CVMX_PREFETCH(address, 0) -#define CVMX_PREFETCH128(address) CVMX_PREFETCH(address, 128) -// a normal prefetch -#define CVMX_PREFETCH(address, offset) CVMX_PREFETCH_PREF0(address, offset) -// normal prefetches that use the pref instruction -#define CVMX_PREFETCH_PREFX(X, address, offset) asm volatile ("pref %[type], %[off](%[rbase])" : : [rbase] "d" (address), [off] "I" (offset), [type] "n" (X)) -#define CVMX_PREFETCH_PREF0(address, offset) CVMX_PREFETCH_PREFX(0, address, offset) -#define CVMX_CLZ(result, input) asm ("clz %[rd],%[rs]" : [rd] "=d" (result) : [rs] "d" (input)) - -#define MAX_RETRIES 3 /* Maximum number of times to retry failed transactions */ -#define MAX_PIPES 32 /* Maximum number of pipes that can be open at once */ -#define MAX_TRANSACTIONS 256 /* Maximum number of outstanding transactions across all pipes */ -#define MAX_CHANNELS 8 /* Maximum number of hardware channels supported by the USB block */ -#define MAX_USB_ADDRESS 127 /* The highest valid USB device address */ -#define MAX_USB_ENDPOINT 15 /* The highest valid USB endpoint number */ -#define MAX_USB_HUB_PORT 15 /* The highest valid port number on a hub */ -#define MAX_TRANSFER_BYTES ((1<<19)-1) /* The low level hardware can transfer a maximum of this number of bytes in each transfer. The field is 19 bits wide */ -#define MAX_TRANSFER_PACKETS ((1<<10)-1) /* The low level hardware can transfer a maximum of this number of packets in each transfer. The field is 10 bits wide */ - -/* - * These defines disable the normal read and write csr. This is so I can add - * extra debug stuff to the usb specific version and I won't use the normal - * version by mistake - */ -#define cvmx_read_csr use_cvmx_usb_read_csr64_instead_of_cvmx_read_csr -#define cvmx_write_csr use_cvmx_usb_write_csr64_instead_of_cvmx_write_csr - -enum cvmx_usb_transaction_flags { - __CVMX_USB_TRANSACTION_FLAGS_IN_USE = 1<<16, -}; - -enum { - USB_CLOCK_TYPE_REF_12, - USB_CLOCK_TYPE_REF_24, - USB_CLOCK_TYPE_REF_48, - USB_CLOCK_TYPE_CRYSTAL_12, -}; - -/** - * Logical transactions may take numerous low level - * transactions, especially when splits are concerned. This - * enum represents all of the possible stages a transaction can - * be in. Note that split completes are always even. This is so - * the NAK handler can backup to the previous low level - * transaction with a simple clearing of bit 0. - */ -enum cvmx_usb_stage { - CVMX_USB_STAGE_NON_CONTROL, - CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE, - CVMX_USB_STAGE_SETUP, - CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE, - CVMX_USB_STAGE_DATA, - CVMX_USB_STAGE_DATA_SPLIT_COMPLETE, - CVMX_USB_STAGE_STATUS, - CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE, -}; - -/** - * struct cvmx_usb_transaction - describes each pending USB transaction - * regardless of type. These are linked together - * to form a list of pending requests for a pipe. - * - * @prev: Transaction before this one in the pipe. - * @next: Transaction after this one in the pipe. - * @type: Type of transaction, duplicated of the pipe. - * @flags: State flags for this transaction. - * @buffer: User's physical buffer address to read/write. - * @buffer_length: Size of the user's buffer in bytes. - * @control_header: For control transactions, physical address of the 8 - * byte standard header. - * @iso_start_frame: For ISO transactions, the starting frame number. - * @iso_number_packets: For ISO transactions, the number of packets in the - * request. - * @iso_packets: For ISO transactions, the sub packets in the request. - * @actual_bytes: Actual bytes transfer for this transaction. - * @stage: For control transactions, the current stage. - * @callback: User's callback function when complete. - * @callback_data: User's data. - */ -struct cvmx_usb_transaction { - struct cvmx_usb_transaction *prev; - struct cvmx_usb_transaction *next; - enum cvmx_usb_transfer type; - enum cvmx_usb_transaction_flags flags; - uint64_t buffer; - int buffer_length; - uint64_t control_header; - int iso_start_frame; - int iso_number_packets; - struct cvmx_usb_iso_packet *iso_packets; - int xfersize; - int pktcnt; - int retries; - int actual_bytes; - enum cvmx_usb_stage stage; - cvmx_usb_callback_func_t callback; - void *callback_data; -}; - -/** - * struct cvmx_usb_pipe - a pipe represents a virtual connection between Octeon - * and some USB device. It contains a list of pending - * request to the device. - * - * @prev: Pipe before this one in the list - * @next: Pipe after this one in the list - * @head: The first pending transaction - * @tail: The last pending transaction - * @interval: For periodic pipes, the interval between packets in - * frames - * @next_tx_frame: The next frame this pipe is allowed to transmit on - * @flags: State flags for this pipe - * @device_speed: Speed of device connected to this pipe - * @transfer_type: Type of transaction supported by this pipe - * @transfer_dir: IN or OUT. Ignored for Control - * @multi_count: Max packet in a row for the device - * @max_packet: The device's maximum packet size in bytes - * @device_addr: USB device address at other end of pipe - * @endpoint_num: USB endpoint number at other end of pipe - * @hub_device_addr: Hub address this device is connected to - * @hub_port: Hub port this device is connected to - * @pid_toggle: This toggles between 0/1 on every packet send to track - * the data pid needed - * @channel: Hardware DMA channel for this pipe - * @split_sc_frame: The low order bits of the frame number the split - * complete should be sent on - */ -struct cvmx_usb_pipe { - struct cvmx_usb_pipe *prev; - struct cvmx_usb_pipe *next; - struct cvmx_usb_transaction *head; - struct cvmx_usb_transaction *tail; - uint64_t interval; - uint64_t next_tx_frame; - enum cvmx_usb_pipe_flags flags; - enum cvmx_usb_speed device_speed; - enum cvmx_usb_transfer transfer_type; - enum cvmx_usb_direction transfer_dir; - int multi_count; - uint16_t max_packet; - uint8_t device_addr; - uint8_t endpoint_num; - uint8_t hub_device_addr; - uint8_t hub_port; - uint8_t pid_toggle; - uint8_t channel; - int8_t split_sc_frame; -}; - -/** - * struct cvmx_usb_pipe_list - * - * @head: Head of the list, or NULL if empty. - * @tail: Tail if the list, or NULL if empty. - */ -struct cvmx_usb_pipe_list { - struct cvmx_usb_pipe *head; - struct cvmx_usb_pipe *tail; -}; - -struct cvmx_usb_tx_fifo { - struct { - int channel; - int size; - uint64_t address; - } entry[MAX_CHANNELS+1]; - int head; - int tail; -}; - -/** - * struct cvmx_usb_internal_state - the state of the USB block - * - * init_flags: Flags passed to initialize. - * index: Which USB block this is for. - * idle_hardware_channels: Bit set for every idle hardware channel. - * usbcx_hprt: Stored port status so we don't need to read a CSR to - * determine splits. - * pipe_for_channel: Map channels to pipes. - * free_transaction_head: List of free transactions head. - * free_transaction_tail: List of free transactions tail. - * pipe: Storage for pipes. - * transaction: Storage for transactions. - * callback: User global callbacks. - * callback_data: User data for each callback. - * indent: Used by debug output to indent functions. - * port_status: Last port status used for change notification. - * free_pipes: List of all pipes that are currently closed. - * idle_pipes: List of open pipes that have no transactions. - * active_pipes: Active pipes indexed by transfer type. - * frame_number: Increments every SOF interrupt for time keeping. - * active_split: Points to the current active split, or NULL. - */ -struct cvmx_usb_internal_state { - int init_flags; - int index; - int idle_hardware_channels; - union cvmx_usbcx_hprt usbcx_hprt; - struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS]; - struct cvmx_usb_transaction *free_transaction_head; - struct cvmx_usb_transaction *free_transaction_tail; - struct cvmx_usb_pipe pipe[MAX_PIPES]; - struct cvmx_usb_transaction transaction[MAX_TRANSACTIONS]; - cvmx_usb_callback_func_t callback[__CVMX_USB_CALLBACK_END]; - void *callback_data[__CVMX_USB_CALLBACK_END]; - int indent; - struct cvmx_usb_port_status port_status; - struct cvmx_usb_pipe_list free_pipes; - struct cvmx_usb_pipe_list idle_pipes; - struct cvmx_usb_pipe_list active_pipes[4]; - uint64_t frame_number; - struct cvmx_usb_transaction *active_split; - struct cvmx_usb_tx_fifo periodic; - struct cvmx_usb_tx_fifo nonperiodic; -}; - -/* This macro spins on a field waiting for it to reach a value */ -#define CVMX_WAIT_FOR_FIELD32(address, type, field, op, value, timeout_usec)\ - ({int result; \ - do { \ - uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \ - octeon_get_clock_rate() / 1000000; \ - type c; \ - while (1) { \ - c.u32 = __cvmx_usb_read_csr32(usb, address); \ - if (c.s.field op (value)) { \ - result = 0; \ - break; \ - } else if (cvmx_get_cycle() > done) { \ - result = -1; \ - break; \ - } else \ - cvmx_wait(100); \ - } \ - } while (0); \ - result; }) - -/* - * This macro logically sets a single field in a CSR. It does the sequence - * read, modify, and write - */ -#define USB_SET_FIELD32(address, type, field, value) \ - do { \ - type c; \ - c.u32 = __cvmx_usb_read_csr32(usb, address); \ - c.s.field = value; \ - __cvmx_usb_write_csr32(usb, address, c.u32); \ - } while (0) - -/* Returns the IO address to push/pop stuff data from the FIFOs */ -#define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000) - -static int octeon_usb_get_clock_type(void) -{ - switch (cvmx_sysinfo_get()->board_type) { - case CVMX_BOARD_TYPE_BBGW_REF: - case CVMX_BOARD_TYPE_LANAI2_A: - case CVMX_BOARD_TYPE_LANAI2_U: - case CVMX_BOARD_TYPE_LANAI2_G: - case CVMX_BOARD_TYPE_UBNT_E100: - return USB_CLOCK_TYPE_CRYSTAL_12; - } - return USB_CLOCK_TYPE_REF_48; -} - -/** - * Read a USB 32bit CSR. It performs the necessary address swizzle - * for 32bit CSRs and logs the value in a readable format if - * debugging is on. - * - * @usb: USB block this access is for - * @address: 64bit address to read - * - * Returns: Result of the read - */ -static inline uint32_t __cvmx_usb_read_csr32(struct cvmx_usb_internal_state *usb, - uint64_t address) -{ - uint32_t result = cvmx_read64_uint32(address ^ 4); - return result; -} - - -/** - * Write a USB 32bit CSR. It performs the necessary address - * swizzle for 32bit CSRs and logs the value in a readable format - * if debugging is on. - * - * @usb: USB block this access is for - * @address: 64bit address to write - * @value: Value to write - */ -static inline void __cvmx_usb_write_csr32(struct cvmx_usb_internal_state *usb, - uint64_t address, uint32_t value) -{ - cvmx_write64_uint32(address ^ 4, value); - cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); -} - - -/** - * Read a USB 64bit CSR. It logs the value in a readable format if - * debugging is on. - * - * @usb: USB block this access is for - * @address: 64bit address to read - * - * Returns: Result of the read - */ -static inline uint64_t __cvmx_usb_read_csr64(struct cvmx_usb_internal_state *usb, - uint64_t address) -{ - uint64_t result = cvmx_read64_uint64(address); - return result; -} - - -/** - * Write a USB 64bit CSR. It logs the value in a readable format - * if debugging is on. - * - * @usb: USB block this access is for - * @address: 64bit address to write - * @value: Value to write - */ -static inline void __cvmx_usb_write_csr64(struct cvmx_usb_internal_state *usb, - uint64_t address, uint64_t value) -{ - cvmx_write64_uint64(address, value); -} - -/** - * Return non zero if this pipe connects to a non HIGH speed - * device through a high speed hub. - * - * @usb: USB block this access is for - * @pipe: Pipe to check - * - * Returns: Non zero if we need to do split transactions - */ -static inline int __cvmx_usb_pipe_needs_split(struct cvmx_usb_internal_state *usb, struct cvmx_usb_pipe *pipe) -{ - return ((pipe->device_speed != CVMX_USB_SPEED_HIGH) && (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH)); -} - - -/** - * Trivial utility function to return the correct PID for a pipe - * - * @pipe: pipe to check - * - * Returns: PID for pipe - */ -static inline int __cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe) -{ - if (pipe->pid_toggle) - return 2; /* Data1 */ - else - return 0; /* Data0 */ -} - - -/** - * Return the number of USB ports supported by this Octeon - * chip. If the chip doesn't support USB, or is not supported - * by this API, a zero will be returned. Most Octeon chips - * support one usb port, but some support two ports. - * cvmx_usb_initialize() must be called on independent - * struct cvmx_usb_state. - * - * Returns: Number of port, zero if usb isn't supported - */ -int cvmx_usb_get_num_ports(void) -{ - int arch_ports = 0; - - if (OCTEON_IS_MODEL(OCTEON_CN56XX)) - arch_ports = 1; - else if (OCTEON_IS_MODEL(OCTEON_CN52XX)) - arch_ports = 2; - else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) - arch_ports = 1; - else if (OCTEON_IS_MODEL(OCTEON_CN31XX)) - arch_ports = 1; - else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) - arch_ports = 1; - else - arch_ports = 0; - - return arch_ports; -} - - -/** - * Allocate a usb transaction for use - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * - * Returns: Transaction or NULL - */ -static inline struct cvmx_usb_transaction *__cvmx_usb_alloc_transaction(struct cvmx_usb_internal_state *usb) -{ - struct cvmx_usb_transaction *t; - t = usb->free_transaction_head; - if (t) { - usb->free_transaction_head = t->next; - if (!usb->free_transaction_head) - usb->free_transaction_tail = NULL; - } - if (t) { - memset(t, 0, sizeof(*t)); - t->flags = __CVMX_USB_TRANSACTION_FLAGS_IN_USE; - } - return t; -} - - -/** - * Free a usb transaction - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @transaction: - * Transaction to free - */ -static inline void __cvmx_usb_free_transaction(struct cvmx_usb_internal_state *usb, - struct cvmx_usb_transaction *transaction) -{ - transaction->flags = 0; - transaction->prev = NULL; - transaction->next = NULL; - if (usb->free_transaction_tail) - usb->free_transaction_tail->next = transaction; - else - usb->free_transaction_head = transaction; - usb->free_transaction_tail = transaction; -} - - -/** - * Add a pipe to the tail of a list - * @list: List to add pipe to - * @pipe: Pipe to add - */ -static inline void __cvmx_usb_append_pipe(struct cvmx_usb_pipe_list *list, struct cvmx_usb_pipe *pipe) -{ - pipe->next = NULL; - pipe->prev = list->tail; - if (list->tail) - list->tail->next = pipe; - else - list->head = pipe; - list->tail = pipe; -} - - -/** - * Remove a pipe from a list - * @list: List to remove pipe from - * @pipe: Pipe to remove - */ -static inline void __cvmx_usb_remove_pipe(struct cvmx_usb_pipe_list *list, struct cvmx_usb_pipe *pipe) -{ - if (list->head == pipe) { - list->head = pipe->next; - pipe->next = NULL; - if (list->head) - list->head->prev = NULL; - else - list->tail = NULL; - } else if (list->tail == pipe) { - list->tail = pipe->prev; - list->tail->next = NULL; - pipe->prev = NULL; - } else { - pipe->prev->next = pipe->next; - pipe->next->prev = pipe->prev; - pipe->prev = NULL; - pipe->next = NULL; - } -} - - -/** - * Initialize a USB port for use. This must be called before any - * other access to the Octeon USB port is made. The port starts - * off in the disabled state. - * - * @state: Pointer to an empty struct cvmx_usb_state - * that will be populated by the initialize call. - * This structure is then passed to all other USB - * functions. - * @usb_port_number: - * Which Octeon USB port to initialize. - * @flags: Flags to control hardware initialization. See - * enum cvmx_usb_initialize_flags for the flag - * definitions. Some flags are mandatory. - * - * Returns: 0 or a negative error code. - */ -int cvmx_usb_initialize(struct cvmx_usb_state *state, int usb_port_number, - enum cvmx_usb_initialize_flags flags) -{ - union cvmx_usbnx_clk_ctl usbn_clk_ctl; - union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - usb->init_flags = flags; - - /* Make sure that state is large enough to store the internal state */ - if (sizeof(*state) < sizeof(*usb)) - return -EINVAL; - /* At first allow 0-1 for the usb port number */ - if ((usb_port_number < 0) || (usb_port_number > 1)) - return -EINVAL; - /* For all chips except 52XX there is only one port */ - if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0)) - return -EINVAL; - /* Try to determine clock type automatically */ - if ((flags & (CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI | - CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND)) == 0) { - if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12) - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI; /* Only 12 MHZ crystals are supported */ - else - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND; - } - - if (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) { - /* Check for auto ref clock frequency */ - if (!(flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK)) - switch (octeon_usb_get_clock_type()) { - case USB_CLOCK_TYPE_REF_12: - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ; - break; - case USB_CLOCK_TYPE_REF_24: - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ; - break; - case USB_CLOCK_TYPE_REF_48: - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ; - break; - default: - return -EINVAL; - break; - } - } - - memset(usb, 0, sizeof(*usb)); - usb->init_flags = flags; - - /* Initialize the USB state structure */ - { - int i; - usb->index = usb_port_number; - - /* Initialize the transaction double linked list */ - usb->free_transaction_head = NULL; - usb->free_transaction_tail = NULL; - for (i = 0; i < MAX_TRANSACTIONS; i++) - __cvmx_usb_free_transaction(usb, usb->transaction + i); - for (i = 0; i < MAX_PIPES; i++) - __cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i); - } - - /* - * Power On Reset and PHY Initialization - * - * 1. Wait for DCOK to assert (nothing to do) - * - * 2a. Write USBN0/1_CLK_CTL[POR] = 1 and - * USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0 - */ - usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index)); - usbn_clk_ctl.s.por = 1; - usbn_clk_ctl.s.hrst = 0; - usbn_clk_ctl.s.prst = 0; - usbn_clk_ctl.s.hclk_rst = 0; - usbn_clk_ctl.s.enable = 0; - /* - * 2b. Select the USB reference clock/crystal parameters by writing - * appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON] - */ - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) { - /* - * The USB port uses 12/24/48MHz 2.5V board clock - * source at USB_XO. USB_XI should be tied to GND. - * Most Octeon evaluation boards require this setting - */ - if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { - usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */ - usbn_clk_ctl.cn31xx.p_xenbn = 0; - } else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) - usbn_clk_ctl.cn56xx.p_rtype = 2; /* From CN56XX,CN50XX manual */ - else - usbn_clk_ctl.cn52xx.p_rtype = 1; /* From CN52XX manual */ - - switch (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) { - case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ: - usbn_clk_ctl.s.p_c_sel = 0; - break; - case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ: - usbn_clk_ctl.s.p_c_sel = 1; - break; - case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ: - usbn_clk_ctl.s.p_c_sel = 2; - break; - } - } else { - /* - * The USB port uses a 12MHz crystal as clock source - * at USB_XO and USB_XI - */ - if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { - usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */ - usbn_clk_ctl.cn31xx.p_xenbn = 1; - } else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) - usbn_clk_ctl.cn56xx.p_rtype = 0; /* From CN56XX,CN50XX manual */ - else - usbn_clk_ctl.cn52xx.p_rtype = 0; /* From CN52XX manual */ - - usbn_clk_ctl.s.p_c_sel = 0; - } - /* - * 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and - * setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down - * such that USB is as close as possible to 125Mhz - */ - { - int divisor = (octeon_get_clock_rate()+125000000-1)/125000000; - if (divisor < 4) /* Lower than 4 doesn't seem to work properly */ - divisor = 4; - usbn_clk_ctl.s.divide = divisor; - usbn_clk_ctl.s.divide2 = 0; - } - __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), - usbn_clk_ctl.u64); - /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */ - usbn_clk_ctl.s.hclk_rst = 1; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), - usbn_clk_ctl.u64); - /* 2e. Wait 64 core-clock cycles for HCLK to stabilize */ - cvmx_wait(64); - /* - * 3. Program the power-on reset field in the USBN clock-control - * register: - * USBN_CLK_CTL[POR] = 0 - */ - usbn_clk_ctl.s.por = 0; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), - usbn_clk_ctl.u64); - /* 4. Wait 1 ms for PHY clock to start */ - mdelay(1); - /* - * 5. Program the Reset input from automatic test equipment field in the - * USBP control and status register: - * USBN_USBP_CTL_STATUS[ATE_RESET] = 1 - */ - usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index)); - usbn_usbp_ctl_status.s.ate_reset = 1; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), - usbn_usbp_ctl_status.u64); - /* 6. Wait 10 cycles */ - cvmx_wait(10); - /* - * 7. Clear ATE_RESET field in the USBN clock-control register: - * USBN_USBP_CTL_STATUS[ATE_RESET] = 0 - */ - usbn_usbp_ctl_status.s.ate_reset = 0; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), - usbn_usbp_ctl_status.u64); - /* - * 8. Program the PHY reset field in the USBN clock-control register: - * USBN_CLK_CTL[PRST] = 1 - */ - usbn_clk_ctl.s.prst = 1; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), - usbn_clk_ctl.u64); - /* - * 9. Program the USBP control and status register to select host or - * device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for - * device - */ - usbn_usbp_ctl_status.s.hst_mode = 0; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), - usbn_usbp_ctl_status.u64); - /* 10. Wait 1 us */ - udelay(1); - /* - * 11. Program the hreset_n field in the USBN clock-control register: - * USBN_CLK_CTL[HRST] = 1 - */ - usbn_clk_ctl.s.hrst = 1; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), - usbn_clk_ctl.u64); - /* 12. Proceed to USB core initialization */ - usbn_clk_ctl.s.enable = 1; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), - usbn_clk_ctl.u64); - udelay(1); - - /* - * USB Core Initialization - * - * 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to - * determine USB core configuration parameters. - * - * Nothing needed - * - * 2. Program the following fields in the global AHB configuration - * register (USBC_GAHBCFG) - * DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode - * Burst length, USBC_GAHBCFG[HBSTLEN] = 0 - * Nonperiodic TxFIFO empty level (slave mode only), - * USBC_GAHBCFG[NPTXFEMPLVL] - * Periodic TxFIFO empty level (slave mode only), - * USBC_GAHBCFG[PTXFEMPLVL] - * Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 - */ - { - union cvmx_usbcx_gahbcfg usbcx_gahbcfg; - /* Due to an errata, CN31XX doesn't support DMA */ - if (OCTEON_IS_MODEL(OCTEON_CN31XX)) - usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA; - usbcx_gahbcfg.u32 = 0; - usbcx_gahbcfg.s.dmaen = !(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA); - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) - usb->idle_hardware_channels = 0x1; /* Only use one channel with non DMA */ - else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) - usb->idle_hardware_channels = 0xf7; /* CN5XXX have an errata with channel 3 */ - else - usb->idle_hardware_channels = 0xff; - usbcx_gahbcfg.s.hbstlen = 0; - usbcx_gahbcfg.s.nptxfemplvl = 1; - usbcx_gahbcfg.s.ptxfemplvl = 1; - usbcx_gahbcfg.s.glblintrmsk = 1; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index), - usbcx_gahbcfg.u32); - } - /* - * 3. Program the following fields in USBC_GUSBCFG register. - * HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0 - * ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0 - * USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5 - * PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0 - */ - { - union cvmx_usbcx_gusbcfg usbcx_gusbcfg; - usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index)); - usbcx_gusbcfg.s.toutcal = 0; - usbcx_gusbcfg.s.ddrsel = 0; - usbcx_gusbcfg.s.usbtrdtim = 0x5; - usbcx_gusbcfg.s.phylpwrclksel = 0; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index), - usbcx_gusbcfg.u32); - } - /* - * 4. The software must unmask the following bits in the USBC_GINTMSK - * register. - * OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1 - * Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1 - */ - { - union cvmx_usbcx_gintmsk usbcx_gintmsk; - int channel; - - usbcx_gintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index)); - usbcx_gintmsk.s.otgintmsk = 1; - usbcx_gintmsk.s.modemismsk = 1; - usbcx_gintmsk.s.hchintmsk = 1; - usbcx_gintmsk.s.sofmsk = 0; - /* We need RX FIFO interrupts if we don't have DMA */ - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) - usbcx_gintmsk.s.rxflvlmsk = 1; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index), - usbcx_gintmsk.u32); - - /* Disable all channel interrupts. We'll enable them per channel later */ - for (channel = 0; channel < 8; channel++) - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0); - } - - { - /* - * Host Port Initialization - * - * 1. Program the host-port interrupt-mask field to unmask, - * USBC_GINTMSK[PRTINT] = 1 - */ - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, - prtintmsk, 1); - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, - disconnintmsk, 1); - /* - * 2. Program the USBC_HCFG register to select full-speed host - * or high-speed host. - */ - { - union cvmx_usbcx_hcfg usbcx_hcfg; - usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index)); - usbcx_hcfg.s.fslssupp = 0; - usbcx_hcfg.s.fslspclksel = 0; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32); - } - /* - * 3. Program the port power bit to drive VBUS on the USB, - * USBC_HPRT[PRTPWR] = 1 - */ - USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtpwr, 1); - - /* - * Steps 4-15 from the manual are done later in the port enable - */ - } - - return 0; -} - - -/** - * Shutdown a USB port after a call to cvmx_usb_initialize(). - * The port should be disabled with all pipes closed when this - * function is called. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * - * Returns: 0 or a negative error code. - */ -int cvmx_usb_shutdown(struct cvmx_usb_state *state) -{ - union cvmx_usbnx_clk_ctl usbn_clk_ctl; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - /* Make sure all pipes are closed */ - if (usb->idle_pipes.head || - usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS].head || - usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT].head || - usb->active_pipes[CVMX_USB_TRANSFER_CONTROL].head || - usb->active_pipes[CVMX_USB_TRANSFER_BULK].head) - return -EBUSY; - - /* Disable the clocks and put them in power on reset */ - usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index)); - usbn_clk_ctl.s.enable = 1; - usbn_clk_ctl.s.por = 1; - usbn_clk_ctl.s.hclk_rst = 1; - usbn_clk_ctl.s.prst = 0; - usbn_clk_ctl.s.hrst = 0; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), - usbn_clk_ctl.u64); - return 0; -} - - -/** - * Enable a USB port. After this call succeeds, the USB port is - * online and servicing requests. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * - * Returns: 0 or a negative error code. - */ -int cvmx_usb_enable(struct cvmx_usb_state *state) -{ - union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); - - /* - * If the port is already enabled the just return. We don't need to do - * anything - */ - if (usb->usbcx_hprt.s.prtena) - return 0; - - /* If there is nothing plugged into the port then fail immediately */ - if (!usb->usbcx_hprt.s.prtconnsts) { - return -ETIMEDOUT; - } - - /* Program the port reset bit to start the reset process */ - USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 1); - - /* - * Wait at least 50ms (high speed), or 10ms (full speed) for the reset - * process to complete. - */ - mdelay(50); - - /* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */ - USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 0); - - /* Wait for the USBC_HPRT[PRTENA]. */ - if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, - prtena, ==, 1, 100000)) - return -ETIMEDOUT; - - /* Read the port speed field to get the enumerated speed, USBC_HPRT[PRTSPD]. */ - usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); - usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index)); - - /* - * 13. Program the USBC_GRXFSIZ register to select the size of the - * receive FIFO (25%). - */ - USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), union cvmx_usbcx_grxfsiz, - rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4); - /* - * 14. Program the USBC_GNPTXFSIZ register to select the size and the - * start address of the non- periodic transmit FIFO for nonperiodic - * transactions (50%). - */ - { - union cvmx_usbcx_gnptxfsiz siz; - siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index)); - siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2; - siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32); - } - /* - * 15. Program the USBC_HPTXFSIZ register to select the size and start - * address of the periodic transmit FIFO for periodic transactions - * (25%). - */ - { - union cvmx_usbcx_hptxfsiz siz; - siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index)); - siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4; - siz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), siz.u32); - } - /* Flush all FIFOs */ - USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfnum, 0x10); - USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfflsh, 1); - CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, - txfflsh, ==, 0, 100); - USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, rxfflsh, 1); - CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, - rxfflsh, ==, 0, 100); - - return 0; -} - - -/** - * Disable a USB port. After this call the USB port will not - * generate data transfers and will not generate events. - * Transactions in process will fail and call their - * associated callbacks. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * - * Returns: 0 or a negative error code. - */ -int cvmx_usb_disable(struct cvmx_usb_state *state) -{ - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - /* Disable the port */ - USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtena, 1); - return 0; -} - - -/** - * Get the current state of the USB port. Use this call to - * determine if the usb port has anything connected, is enabled, - * or has some sort of error condition. The return value of this - * call has "changed" bits to signal of the value of some fields - * have changed between calls. These "changed" fields are based - * on the last call to cvmx_usb_set_status(). In order to clear - * them, you must update the status through cvmx_usb_set_status(). - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * - * Returns: Port status information - */ -struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *state) -{ - union cvmx_usbcx_hprt usbc_hprt; - struct cvmx_usb_port_status result; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - memset(&result, 0, sizeof(result)); - - usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); - result.port_enabled = usbc_hprt.s.prtena; - result.port_over_current = usbc_hprt.s.prtovrcurract; - result.port_powered = usbc_hprt.s.prtpwr; - result.port_speed = usbc_hprt.s.prtspd; - result.connected = usbc_hprt.s.prtconnsts; - result.connect_change = (result.connected != usb->port_status.connected); - - return result; -} - - -/** - * Set the current state of the USB port. The status is used as - * a reference for the "changed" bits returned by - * cvmx_usb_get_status(). Other than serving as a reference, the - * status passed to this function is not used. No fields can be - * changed through this call. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @port_status: - * Port status to set, most like returned by cvmx_usb_get_status() - */ -void cvmx_usb_set_status(struct cvmx_usb_state *state, struct cvmx_usb_port_status port_status) -{ - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - usb->port_status = port_status; - return; -} - - -/** - * Convert a USB transaction into a handle - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @transaction: - * Transaction to get handle for - * - * Returns: Handle - */ -static inline int __cvmx_usb_get_submit_handle(struct cvmx_usb_internal_state *usb, - struct cvmx_usb_transaction *transaction) -{ - return ((unsigned long)transaction - (unsigned long)usb->transaction) / - sizeof(*transaction); -} - - -/** - * Convert a USB pipe into a handle - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @pipe: Pipe to get handle for - * - * Returns: Handle - */ -static inline int __cvmx_usb_get_pipe_handle(struct cvmx_usb_internal_state *usb, - struct cvmx_usb_pipe *pipe) -{ - return ((unsigned long)pipe - (unsigned long)usb->pipe) / sizeof(*pipe); -} - - -/** - * Open a virtual pipe between the host and a USB device. A pipe - * must be opened before data can be transferred between a device - * and Octeon. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @flags: Optional pipe flags defined in - * enum cvmx_usb_pipe_flags. - * @device_addr: - * USB device address to open the pipe to - * (0-127). - * @endpoint_num: - * USB endpoint number to open the pipe to - * (0-15). - * @device_speed: - * The speed of the device the pipe is going - * to. This must match the device's speed, - * which may be different than the port speed. - * @max_packet: The maximum packet length the device can - * transmit/receive (low speed=0-8, full - * speed=0-1023, high speed=0-1024). This value - * comes from the standard endpoint descriptor - * field wMaxPacketSize bits <10:0>. - * @transfer_type: - * The type of transfer this pipe is for. - * @transfer_dir: - * The direction the pipe is in. This is not - * used for control pipes. - * @interval: For ISOCHRONOUS and INTERRUPT transfers, - * this is how often the transfer is scheduled - * for. All other transfers should specify - * zero. The units are in frames (8000/sec at - * high speed, 1000/sec for full speed). - * @multi_count: - * For high speed devices, this is the maximum - * allowed number of packet per microframe. - * Specify zero for non high speed devices. This - * value comes from the standard endpoint descriptor - * field wMaxPacketSize bits <12:11>. - * @hub_device_addr: - * Hub device address this device is connected - * to. Devices connected directly to Octeon - * use zero. This is only used when the device - * is full/low speed behind a high speed hub. - * The address will be of the high speed hub, - * not and full speed hubs after it. - * @hub_port: Which port on the hub the device is - * connected. Use zero for devices connected - * directly to Octeon. Like hub_device_addr, - * this is only used for full/low speed - * devices behind a high speed hub. - * - * Returns: A non negative value is a pipe handle. Negative - * values are error codes. - */ -int cvmx_usb_open_pipe(struct cvmx_usb_state *state, enum cvmx_usb_pipe_flags flags, - int device_addr, int endpoint_num, - enum cvmx_usb_speed device_speed, int max_packet, - enum cvmx_usb_transfer transfer_type, - enum cvmx_usb_direction transfer_dir, int interval, - int multi_count, int hub_device_addr, int hub_port) -{ - struct cvmx_usb_pipe *pipe; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - if (unlikely((device_addr < 0) || (device_addr > MAX_USB_ADDRESS))) - return -EINVAL; - if (unlikely((endpoint_num < 0) || (endpoint_num > MAX_USB_ENDPOINT))) - return -EINVAL; - if (unlikely(device_speed > CVMX_USB_SPEED_LOW)) - return -EINVAL; - if (unlikely((max_packet <= 0) || (max_packet > 1024))) - return -EINVAL; - if (unlikely(transfer_type > CVMX_USB_TRANSFER_INTERRUPT)) - return -EINVAL; - if (unlikely((transfer_dir != CVMX_USB_DIRECTION_OUT) && - (transfer_dir != CVMX_USB_DIRECTION_IN))) - return -EINVAL; - if (unlikely(interval < 0)) - return -EINVAL; - if (unlikely((transfer_type == CVMX_USB_TRANSFER_CONTROL) && interval)) - return -EINVAL; - if (unlikely(multi_count < 0)) - return -EINVAL; - if (unlikely((device_speed != CVMX_USB_SPEED_HIGH) && - (multi_count != 0))) - return -EINVAL; - if (unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS))) - return -EINVAL; - if (unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT))) - return -EINVAL; - - /* Find a free pipe */ - pipe = usb->free_pipes.head; - if (!pipe) - return -ENOMEM; - __cvmx_usb_remove_pipe(&usb->free_pipes, pipe); - pipe->flags = flags | __CVMX_USB_PIPE_FLAGS_OPEN; - if ((device_speed == CVMX_USB_SPEED_HIGH) && - (transfer_dir == CVMX_USB_DIRECTION_OUT) && - (transfer_type == CVMX_USB_TRANSFER_BULK)) - pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING; - pipe->device_addr = device_addr; - pipe->endpoint_num = endpoint_num; - pipe->device_speed = device_speed; - pipe->max_packet = max_packet; - pipe->transfer_type = transfer_type; - pipe->transfer_dir = transfer_dir; - /* - * All pipes use interval to rate limit NAK processing. Force an - * interval if one wasn't supplied - */ - if (!interval) - interval = 1; - if (__cvmx_usb_pipe_needs_split(usb, pipe)) { - pipe->interval = interval*8; - /* Force start splits to be schedule on uFrame 0 */ - pipe->next_tx_frame = ((usb->frame_number+7)&~7) + pipe->interval; - } else { - pipe->interval = interval; - pipe->next_tx_frame = usb->frame_number + pipe->interval; - } - pipe->multi_count = multi_count; - pipe->hub_device_addr = hub_device_addr; - pipe->hub_port = hub_port; - pipe->pid_toggle = 0; - pipe->split_sc_frame = -1; - __cvmx_usb_append_pipe(&usb->idle_pipes, pipe); - - /* - * We don't need to tell the hardware about this pipe yet since - * it doesn't have any submitted requests - */ - - return __cvmx_usb_get_pipe_handle(usb, pipe); -} - - -/** - * Poll the RX FIFOs and remove data as needed. This function is only used - * in non DMA mode. It is very important that this function be called quickly - * enough to prevent FIFO overflow. - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - */ -static void __cvmx_usb_poll_rx_fifo(struct cvmx_usb_internal_state *usb) -{ - union cvmx_usbcx_grxstsph rx_status; - int channel; - int bytes; - uint64_t address; - uint32_t *ptr; - - rx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GRXSTSPH(usb->index)); - /* Only read data if IN data is there */ - if (rx_status.s.pktsts != 2) - return; - /* Check if no data is available */ - if (!rx_status.s.bcnt) - return; - - channel = rx_status.s.chnum; - bytes = rx_status.s.bcnt; - if (!bytes) - return; - - /* Get where the DMA engine would have written this data */ - address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8); - ptr = cvmx_phys_to_ptr(address); - __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, address + bytes); - - /* Loop writing the FIFO data for this packet into memory */ - while (bytes > 0) { - *ptr++ = __cvmx_usb_read_csr32(usb, USB_FIFO_ADDRESS(channel, usb->index)); - bytes -= 4; - } - CVMX_SYNCW; - - return; -} - - -/** - * Fill the TX hardware fifo with data out of the software - * fifos - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @fifo: Software fifo to use - * @available: Amount of space in the hardware fifo - * - * Returns: Non zero if the hardware fifo was too small and needs - * to be serviced again. - */ -static int __cvmx_usb_fill_tx_hw(struct cvmx_usb_internal_state *usb, struct cvmx_usb_tx_fifo *fifo, int available) -{ - /* - * We're done either when there isn't anymore space or the software FIFO - * is empty - */ - while (available && (fifo->head != fifo->tail)) { - int i = fifo->tail; - const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address); - uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel, usb->index) ^ 4; - int words = available; - - /* Limit the amount of data to waht the SW fifo has */ - if (fifo->entry[i].size <= available) { - words = fifo->entry[i].size; - fifo->tail++; - if (fifo->tail > MAX_CHANNELS) - fifo->tail = 0; - } - - /* Update the next locations and counts */ - available -= words; - fifo->entry[i].address += words * 4; - fifo->entry[i].size -= words; - - /* - * Write the HW fifo data. The read every three writes is due - * to an errata on CN3XXX chips - */ - while (words > 3) { - cvmx_write64_uint32(csr_address, *ptr++); - cvmx_write64_uint32(csr_address, *ptr++); - cvmx_write64_uint32(csr_address, *ptr++); - cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); - words -= 3; - } - cvmx_write64_uint32(csr_address, *ptr++); - if (--words) { - cvmx_write64_uint32(csr_address, *ptr++); - if (--words) - cvmx_write64_uint32(csr_address, *ptr++); - } - cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); - } - return fifo->head != fifo->tail; -} - - -/** - * Check the hardware FIFOs and fill them as needed - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - */ -static void __cvmx_usb_poll_tx_fifo(struct cvmx_usb_internal_state *usb) -{ - if (usb->periodic.head != usb->periodic.tail) { - union cvmx_usbcx_hptxsts tx_status; - tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXSTS(usb->index)); - if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic, tx_status.s.ptxfspcavail)) - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 1); - else - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 0); - } - - if (usb->nonperiodic.head != usb->nonperiodic.tail) { - union cvmx_usbcx_gnptxsts tx_status; - tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXSTS(usb->index)); - if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, tx_status.s.nptxfspcavail)) - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 1); - else - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 0); - } - - return; -} - - -/** - * Fill the TX FIFO with an outgoing packet - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @channel: Channel number to get packet from - */ -static void __cvmx_usb_fill_tx_fifo(struct cvmx_usb_internal_state *usb, int channel) -{ - union cvmx_usbcx_hccharx hcchar; - union cvmx_usbcx_hcspltx usbc_hcsplt; - union cvmx_usbcx_hctsizx usbc_hctsiz; - struct cvmx_usb_tx_fifo *fifo; - - /* We only need to fill data on outbound channels */ - hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index)); - if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT) - return; - - /* OUT Splits only have data on the start and not the complete */ - usbc_hcsplt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index)); - if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt) - return; - - /* Find out how many bytes we need to fill and convert it into 32bit words */ - usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index)); - if (!usbc_hctsiz.s.xfersize) - return; - - if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) || - (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS)) - fifo = &usb->periodic; - else - fifo = &usb->nonperiodic; - - fifo->entry[fifo->head].channel = channel; - fifo->entry[fifo->head].address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8); - fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize+3)>>2; - fifo->head++; - if (fifo->head > MAX_CHANNELS) - fifo->head = 0; - - __cvmx_usb_poll_tx_fifo(usb); - - return; -} - -/** - * Perform channel specific setup for Control transactions. All - * the generic stuff will already have been done in - * __cvmx_usb_start_channel() - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @channel: Channel to setup - * @pipe: Pipe for control transaction - */ -static void __cvmx_usb_start_channel_control(struct cvmx_usb_internal_state *usb, - int channel, - struct cvmx_usb_pipe *pipe) -{ - struct cvmx_usb_transaction *transaction = pipe->head; - union cvmx_usb_control_header *header = - cvmx_phys_to_ptr(transaction->control_header); - int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes; - int packets_to_transfer; - union cvmx_usbcx_hctsizx usbc_hctsiz; - - usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index)); - - switch (transaction->stage) { - case CVMX_USB_STAGE_NON_CONTROL: - case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE: - cvmx_dprintf("%s: ERROR - Non control stage\n", __FUNCTION__); - break; - case CVMX_USB_STAGE_SETUP: - usbc_hctsiz.s.pid = 3; /* Setup */ - bytes_to_transfer = sizeof(*header); - /* All Control operations start with a setup going OUT */ - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT); - /* - * Setup send the control header instead of the buffer data. The - * buffer data will be used in the next stage - */ - __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header); - break; - case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE: - usbc_hctsiz.s.pid = 3; /* Setup */ - bytes_to_transfer = 0; - /* All Control operations start with a setup going OUT */ - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT); - USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1); - break; - case CVMX_USB_STAGE_DATA: - usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); - if (__cvmx_usb_pipe_needs_split(usb, pipe)) { - if (header->s.request_type & 0x80) - bytes_to_transfer = 0; - else if (bytes_to_transfer > pipe->max_packet) - bytes_to_transfer = pipe->max_packet; - } - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), - union cvmx_usbcx_hccharx, epdir, - ((header->s.request_type & 0x80) ? - CVMX_USB_DIRECTION_IN : - CVMX_USB_DIRECTION_OUT)); - break; - case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE: - usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); - if (!(header->s.request_type & 0x80)) - bytes_to_transfer = 0; - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), - union cvmx_usbcx_hccharx, epdir, - ((header->s.request_type & 0x80) ? - CVMX_USB_DIRECTION_IN : - CVMX_USB_DIRECTION_OUT)); - USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1); - break; - case CVMX_USB_STAGE_STATUS: - usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); - bytes_to_transfer = 0; - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, - ((header->s.request_type & 0x80) ? - CVMX_USB_DIRECTION_OUT : - CVMX_USB_DIRECTION_IN)); - break; - case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE: - usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); - bytes_to_transfer = 0; - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, - ((header->s.request_type & 0x80) ? - CVMX_USB_DIRECTION_OUT : - CVMX_USB_DIRECTION_IN)); - USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1); - break; - } - - /* - * Make sure the transfer never exceeds the byte limit of the hardware. - * Further bytes will be sent as continued transactions - */ - if (bytes_to_transfer > MAX_TRANSFER_BYTES) { - /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */ - bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet; - bytes_to_transfer *= pipe->max_packet; - } - - /* - * Calculate the number of packets to transfer. If the length is zero - * we still need to transfer one packet - */ - packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet; - if (packets_to_transfer == 0) - packets_to_transfer = 1; - else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) { - /* - * Limit to one packet when not using DMA. Channels must be - * restarted between every packet for IN transactions, so there - * is no reason to do multiple packets in a row - */ - packets_to_transfer = 1; - bytes_to_transfer = packets_to_transfer * pipe->max_packet; - } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) { - /* - * Limit the number of packet and data transferred to what the - * hardware can handle - */ - packets_to_transfer = MAX_TRANSFER_PACKETS; - bytes_to_transfer = packets_to_transfer * pipe->max_packet; - } - - usbc_hctsiz.s.xfersize = bytes_to_transfer; - usbc_hctsiz.s.pktcnt = packets_to_transfer; - - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32); - return; -} - - -/** - * Start a channel to perform the pipe's head transaction - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @channel: Channel to setup - * @pipe: Pipe to start - */ -static void __cvmx_usb_start_channel(struct cvmx_usb_internal_state *usb, - int channel, - struct cvmx_usb_pipe *pipe) -{ - struct cvmx_usb_transaction *transaction = pipe->head; - - /* Make sure all writes to the DMA region get flushed */ - CVMX_SYNCW; - - /* Attach the channel to the pipe */ - usb->pipe_for_channel[channel] = pipe; - pipe->channel = channel; - pipe->flags |= __CVMX_USB_PIPE_FLAGS_SCHEDULED; - - /* Mark this channel as in use */ - usb->idle_hardware_channels &= ~(1<<channel); - - /* Enable the channel interrupt bits */ - { - union cvmx_usbcx_hcintx usbc_hcint; - union cvmx_usbcx_hcintmskx usbc_hcintmsk; - union cvmx_usbcx_haintmsk usbc_haintmsk; - - /* Clear all channel status bits */ - usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index)); - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index), usbc_hcint.u32); - - usbc_hcintmsk.u32 = 0; - usbc_hcintmsk.s.chhltdmsk = 1; - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { - /* Channels need these extra interrupts when we aren't in DMA mode */ - usbc_hcintmsk.s.datatglerrmsk = 1; - usbc_hcintmsk.s.frmovrunmsk = 1; - usbc_hcintmsk.s.bblerrmsk = 1; - usbc_hcintmsk.s.xacterrmsk = 1; - if (__cvmx_usb_pipe_needs_split(usb, pipe)) { - /* Splits don't generate xfercompl, so we need ACK and NYET */ - usbc_hcintmsk.s.nyetmsk = 1; - usbc_hcintmsk.s.ackmsk = 1; - } - usbc_hcintmsk.s.nakmsk = 1; - usbc_hcintmsk.s.stallmsk = 1; - usbc_hcintmsk.s.xfercomplmsk = 1; - } - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), usbc_hcintmsk.u32); - - /* Enable the channel interrupt to propagate */ - usbc_haintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index)); - usbc_haintmsk.s.haintmsk |= 1<<channel; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), usbc_haintmsk.u32); - } - - /* Setup the locations the DMA engines use */ - { - uint64_t dma_address = transaction->buffer + transaction->actual_bytes; - if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) - dma_address = transaction->buffer + transaction->iso_packets[0].offset + transaction->actual_bytes; - __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, dma_address); - __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, dma_address); - } - - /* Setup both the size of the transfer and the SPLIT characteristics */ - { - union cvmx_usbcx_hcspltx usbc_hcsplt = {.u32 = 0}; - union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = 0}; - int packets_to_transfer; - int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes; - - /* - * ISOCHRONOUS transactions store each individual transfer size - * in the packet structure, not the global buffer_length - */ - if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) - bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes; - - /* - * We need to do split transactions when we are talking to non - * high speed devices that are behind a high speed hub - */ - if (__cvmx_usb_pipe_needs_split(usb, pipe)) { - /* - * On the start split phase (stage is even) record the - * frame number we will need to send the split complete. - * We only store the lower two bits since the time ahead - * can only be two frames - */ - if ((transaction->stage&1) == 0) { - if (transaction->type == CVMX_USB_TRANSFER_BULK) - pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f; - else - pipe->split_sc_frame = (usb->frame_number + 2) & 0x7f; - } else - pipe->split_sc_frame = -1; - - usbc_hcsplt.s.spltena = 1; - usbc_hcsplt.s.hubaddr = pipe->hub_device_addr; - usbc_hcsplt.s.prtaddr = pipe->hub_port; - usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE); - - /* - * SPLIT transactions can only ever transmit one data - * packet so limit the transfer size to the max packet - * size - */ - if (bytes_to_transfer > pipe->max_packet) - bytes_to_transfer = pipe->max_packet; - - /* - * ISOCHRONOUS OUT splits are unique in that they limit - * data transfers to 188 byte chunks representing the - * begin/middle/end of the data or all - */ - if (!usbc_hcsplt.s.compsplt && - (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) && - (pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) { - /* - * Clear the split complete frame number as - * there isn't going to be a split complete - */ - pipe->split_sc_frame = -1; - /* - * See if we've started this transfer and sent - * data - */ - if (transaction->actual_bytes == 0) { - /* - * Nothing sent yet, this is either a - * begin or the entire payload - */ - if (bytes_to_transfer <= 188) - usbc_hcsplt.s.xactpos = 3; /* Entire payload in one go */ - else - usbc_hcsplt.s.xactpos = 2; /* First part of payload */ - } else { - /* - * Continuing the previous data, we must - * either be in the middle or at the end - */ - if (bytes_to_transfer <= 188) - usbc_hcsplt.s.xactpos = 1; /* End of payload */ - else - usbc_hcsplt.s.xactpos = 0; /* Middle of payload */ - } - /* - * Again, the transfer size is limited to 188 - * bytes - */ - if (bytes_to_transfer > 188) - bytes_to_transfer = 188; - } - } - - /* - * Make sure the transfer never exceeds the byte limit of the - * hardware. Further bytes will be sent as continued - * transactions - */ - if (bytes_to_transfer > MAX_TRANSFER_BYTES) { - /* - * Round MAX_TRANSFER_BYTES to a multiple of out packet - * size - */ - bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet; - bytes_to_transfer *= pipe->max_packet; - } - - /* - * Calculate the number of packets to transfer. If the length is - * zero we still need to transfer one packet - */ - packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet; - if (packets_to_transfer == 0) - packets_to_transfer = 1; - else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) { - /* - * Limit to one packet when not using DMA. Channels must - * be restarted between every packet for IN - * transactions, so there is no reason to do multiple - * packets in a row - */ - packets_to_transfer = 1; - bytes_to_transfer = packets_to_transfer * pipe->max_packet; - } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) { - /* - * Limit the number of packet and data transferred to - * what the hardware can handle - */ - packets_to_transfer = MAX_TRANSFER_PACKETS; - bytes_to_transfer = packets_to_transfer * pipe->max_packet; - } - - usbc_hctsiz.s.xfersize = bytes_to_transfer; - usbc_hctsiz.s.pktcnt = packets_to_transfer; - - /* Update the DATA0/DATA1 toggle */ - usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); - /* - * High speed pipes may need a hardware ping before they start - */ - if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING) - usbc_hctsiz.s.dopng = 1; - - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index), usbc_hcsplt.u32); - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32); - } - - /* Setup the Host Channel Characteristics Register */ - { - union cvmx_usbcx_hccharx usbc_hcchar = {.u32 = 0}; - - /* - * Set the startframe odd/even properly. This is only used for - * periodic - */ - usbc_hcchar.s.oddfrm = usb->frame_number&1; - - /* - * Set the number of back to back packets allowed by this - * endpoint. Split transactions interpret "ec" as the number of - * immediate retries of failure. These retries happen too - * quickly, so we disable these entirely for splits - */ - if (__cvmx_usb_pipe_needs_split(usb, pipe)) - usbc_hcchar.s.ec = 1; - else if (pipe->multi_count < 1) - usbc_hcchar.s.ec = 1; - else if (pipe->multi_count > 3) - usbc_hcchar.s.ec = 3; - else - usbc_hcchar.s.ec = pipe->multi_count; - - /* Set the rest of the endpoint specific settings */ - usbc_hcchar.s.devaddr = pipe->device_addr; - usbc_hcchar.s.eptype = transaction->type; - usbc_hcchar.s.lspddev = (pipe->device_speed == CVMX_USB_SPEED_LOW); - usbc_hcchar.s.epdir = pipe->transfer_dir; - usbc_hcchar.s.epnum = pipe->endpoint_num; - usbc_hcchar.s.mps = pipe->max_packet; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32); - } - - /* Do transaction type specific fixups as needed */ - switch (transaction->type) { - case CVMX_USB_TRANSFER_CONTROL: - __cvmx_usb_start_channel_control(usb, channel, pipe); - break; - case CVMX_USB_TRANSFER_BULK: - case CVMX_USB_TRANSFER_INTERRUPT: - break; - case CVMX_USB_TRANSFER_ISOCHRONOUS: - if (!__cvmx_usb_pipe_needs_split(usb, pipe)) { - /* - * ISO transactions require different PIDs depending on - * direction and how many packets are needed - */ - if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) { - if (pipe->multi_count < 2) /* Need DATA0 */ - USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 0); - else /* Need MDATA */ - USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 3); - } - } - break; - } - { - union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index))}; - transaction->xfersize = usbc_hctsiz.s.xfersize; - transaction->pktcnt = usbc_hctsiz.s.pktcnt; - } - /* Remeber when we start a split transaction */ - if (__cvmx_usb_pipe_needs_split(usb, pipe)) - usb->active_split = transaction; - USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, chena, 1); - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) - __cvmx_usb_fill_tx_fifo(usb, channel); - return; -} - - -/** - * Find a pipe that is ready to be scheduled to hardware. - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @list: Pipe list to search - * @current_frame: - * Frame counter to use as a time reference. - * - * Returns: Pipe or NULL if none are ready - */ -static struct cvmx_usb_pipe *__cvmx_usb_find_ready_pipe(struct cvmx_usb_internal_state *usb, struct cvmx_usb_pipe_list *list, uint64_t current_frame) -{ - struct cvmx_usb_pipe *pipe = list->head; - while (pipe) { - if (!(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED) && pipe->head && - (pipe->next_tx_frame <= current_frame) && - ((pipe->split_sc_frame == -1) || ((((int)current_frame - (int)pipe->split_sc_frame) & 0x7f) < 0x40)) && - (!usb->active_split || (usb->active_split == pipe->head))) { - CVMX_PREFETCH(pipe, 128); - CVMX_PREFETCH(pipe->head, 0); - return pipe; - } - pipe = pipe->next; - } - return NULL; -} - - -/** - * Called whenever a pipe might need to be scheduled to the - * hardware. - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @is_sof: True if this schedule was called on a SOF interrupt. - */ -static void __cvmx_usb_schedule(struct cvmx_usb_internal_state *usb, int is_sof) -{ - int channel; - struct cvmx_usb_pipe *pipe; - int need_sof; - enum cvmx_usb_transfer ttype; - - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { - /* Without DMA we need to be careful to not schedule something at the end of a frame and cause an overrun */ - union cvmx_usbcx_hfnum hfnum = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index))}; - union cvmx_usbcx_hfir hfir = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFIR(usb->index))}; - if (hfnum.s.frrem < hfir.s.frint/4) - goto done; - } - - while (usb->idle_hardware_channels) { - /* Find an idle channel */ - CVMX_CLZ(channel, usb->idle_hardware_channels); - channel = 31 - channel; - if (unlikely(channel > 7)) - break; - - /* Find a pipe needing service */ - pipe = NULL; - if (is_sof) { - /* - * Only process periodic pipes on SOF interrupts. This - * way we are sure that the periodic data is sent in the - * beginning of the frame - */ - pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number); - if (likely(!pipe)) - pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number); - } - if (likely(!pipe)) { - pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_CONTROL, usb->frame_number); - if (likely(!pipe)) - pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_BULK, usb->frame_number); - } - if (!pipe) - break; - - __cvmx_usb_start_channel(usb, channel, pipe); - } - -done: - /* - * Only enable SOF interrupts when we have transactions pending in the - * future that might need to be scheduled - */ - need_sof = 0; - for (ttype = CVMX_USB_TRANSFER_CONTROL; ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) { - pipe = usb->active_pipes[ttype].head; - while (pipe) { - if (pipe->next_tx_frame > usb->frame_number) { - need_sof = 1; - break; - } - pipe = pipe->next; - } - } - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, sofmsk, need_sof); - return; -} - - -/** - * Call a user's callback for a specific reason. - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @pipe: Pipe the callback is for or NULL - * @transaction: - * Transaction the callback is for or NULL - * @reason: Reason this callback is being called - * @complete_code: - * Completion code for the transaction, if any - */ -static void __cvmx_usb_perform_callback(struct cvmx_usb_internal_state *usb, - struct cvmx_usb_pipe *pipe, - struct cvmx_usb_transaction *transaction, - enum cvmx_usb_callback reason, - enum cvmx_usb_complete complete_code) -{ - cvmx_usb_callback_func_t callback = usb->callback[reason]; - void *user_data = usb->callback_data[reason]; - int submit_handle = -1; - int pipe_handle = -1; - int bytes_transferred = 0; - - if (pipe) - pipe_handle = __cvmx_usb_get_pipe_handle(usb, pipe); - - if (transaction) { - submit_handle = __cvmx_usb_get_submit_handle(usb, transaction); - bytes_transferred = transaction->actual_bytes; - /* Transactions are allowed to override the default callback */ - if ((reason == CVMX_USB_CALLBACK_TRANSFER_COMPLETE) && transaction->callback) { - callback = transaction->callback; - user_data = transaction->callback_data; - } - } - - if (!callback) - return; - - callback((struct cvmx_usb_state *)usb, reason, complete_code, pipe_handle, submit_handle, - bytes_transferred, user_data); -} - - -/** - * Signal the completion of a transaction and free it. The - * transaction will be removed from the pipe transaction list. - * - * @usb: USB device state populated by - * cvmx_usb_initialize(). - * @pipe: Pipe the transaction is on - * @transaction: - * Transaction that completed - * @complete_code: - * Completion code - */ -static void __cvmx_usb_perform_complete(struct cvmx_usb_internal_state *usb, - struct cvmx_usb_pipe *pipe, - struct cvmx_usb_transaction *transaction, - enum cvmx_usb_complete complete_code) -{ - /* If this was a split then clear our split in progress marker */ - if (usb->active_split == transaction) - usb->active_split = NULL; - - /* - * Isochronous transactions need extra processing as they might not be - * done after a single data transfer - */ - if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) { - /* Update the number of bytes transferred in this ISO packet */ - transaction->iso_packets[0].length = transaction->actual_bytes; - transaction->iso_packets[0].status = complete_code; - - /* - * If there are more ISOs pending and we succeeded, schedule the - * next one - */ - if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) { - transaction->actual_bytes = 0; /* No bytes transferred for this packet as of yet */ - transaction->iso_number_packets--; /* One less ISO waiting to transfer */ - transaction->iso_packets++; /* Increment to the next location in our packet array */ - transaction->stage = CVMX_USB_STAGE_NON_CONTROL; - goto done; - } - } - - /* Remove the transaction from the pipe list */ - if (transaction->next) - transaction->next->prev = transaction->prev; - else - pipe->tail = transaction->prev; - if (transaction->prev) - transaction->prev->next = transaction->next; - else - pipe->head = transaction->next; - if (!pipe->head) { - __cvmx_usb_remove_pipe(usb->active_pipes + pipe->transfer_type, pipe); - __cvmx_usb_append_pipe(&usb->idle_pipes, pipe); - - } - __cvmx_usb_perform_callback(usb, pipe, transaction, - CVMX_USB_CALLBACK_TRANSFER_COMPLETE, - complete_code); - __cvmx_usb_free_transaction(usb, transaction); -done: - return; -} - - -/** - * Submit a usb transaction to a pipe. Called for all types - * of transactions. - * - * @usb: - * @pipe_handle: - * Which pipe to submit to. Will be validated in this function. - * @type: Transaction type - * @flags: Flags for the transaction - * @buffer: User buffer for the transaction - * @buffer_length: - * User buffer's length in bytes - * @control_header: - * For control transactions, the 8 byte standard header - * @iso_start_frame: - * For ISO transactions, the start frame - * @iso_number_packets: - * For ISO, the number of packet in the transaction. - * @iso_packets: - * A description of each ISO packet - * @callback: User callback to call when the transaction completes - * @user_data: User's data for the callback - * - * Returns: Submit handle or negative on failure. Matches the result - * in the external API. - */ -static int __cvmx_usb_submit_transaction(struct cvmx_usb_internal_state *usb, - int pipe_handle, - enum cvmx_usb_transfer type, - int flags, - uint64_t buffer, - int buffer_length, - uint64_t control_header, - int iso_start_frame, - int iso_number_packets, - struct cvmx_usb_iso_packet *iso_packets, - cvmx_usb_callback_func_t callback, - void *user_data) -{ - int submit_handle; - struct cvmx_usb_transaction *transaction; - struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle; - - if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES))) - return -EINVAL; - /* Fail if the pipe isn't open */ - if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0)) - return -EINVAL; - if (unlikely(pipe->transfer_type != type)) - return -EINVAL; - - transaction = __cvmx_usb_alloc_transaction(usb); - if (unlikely(!transaction)) - return -ENOMEM; - - transaction->type = type; - transaction->flags |= flags; - transaction->buffer = buffer; - transaction->buffer_length = buffer_length; - transaction->control_header = control_header; - transaction->iso_start_frame = iso_start_frame; // FIXME: This is not used, implement it - transaction->iso_number_packets = iso_number_packets; - transaction->iso_packets = iso_packets; - transaction->callback = callback; - transaction->callback_data = user_data; - if (transaction->type == CVMX_USB_TRANSFER_CONTROL) - transaction->stage = CVMX_USB_STAGE_SETUP; - else - transaction->stage = CVMX_USB_STAGE_NON_CONTROL; - - transaction->next = NULL; - if (pipe->tail) { - transaction->prev = pipe->tail; - transaction->prev->next = transaction; - } else { - if (pipe->next_tx_frame < usb->frame_number) - pipe->next_tx_frame = usb->frame_number + pipe->interval - - (usb->frame_number - pipe->next_tx_frame) % pipe->interval; - transaction->prev = NULL; - pipe->head = transaction; - __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe); - __cvmx_usb_append_pipe(usb->active_pipes + pipe->transfer_type, pipe); - } - pipe->tail = transaction; - - submit_handle = __cvmx_usb_get_submit_handle(usb, transaction); - - /* We may need to schedule the pipe if this was the head of the pipe */ - if (!transaction->prev) - __cvmx_usb_schedule(usb, 0); - - return submit_handle; -} - - -/** - * Call to submit a USB Bulk transfer to a pipe. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @pipe_handle: - * Handle to the pipe for the transfer. - * @buffer: Physical address of the data buffer in - * memory. Note that this is NOT A POINTER, but - * the full 64bit physical address of the - * buffer. This may be zero if buffer_length is - * zero. - * @buffer_length: - * Length of buffer in bytes. - * @callback: Function to call when this transaction - * completes. If the return value of this - * function isn't an error, then this function - * is guaranteed to be called when the - * transaction completes. If this parameter is - * NULL, then the generic callback registered - * through cvmx_usb_register_callback is - * called. If both are NULL, then there is no - * way to know when a transaction completes. - * @user_data: User supplied data returned when the - * callback is called. This is only used if - * callback in not NULL. - * - * Returns: A submitted transaction handle or negative on - * failure. Negative values are error codes. - */ -int cvmx_usb_submit_bulk(struct cvmx_usb_state *state, int pipe_handle, - uint64_t buffer, int buffer_length, - cvmx_usb_callback_func_t callback, - void *user_data) -{ - int submit_handle; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - /* Pipe handle checking is done later in a common place */ - if (unlikely(!buffer)) - return -EINVAL; - if (unlikely(buffer_length < 0)) - return -EINVAL; - - submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle, - CVMX_USB_TRANSFER_BULK, - 0, /* flags */ - buffer, - buffer_length, - 0, /* control_header */ - 0, /* iso_start_frame */ - 0, /* iso_number_packets */ - NULL, /* iso_packets */ - callback, - user_data); - return submit_handle; -} - - -/** - * Call to submit a USB Interrupt transfer to a pipe. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @pipe_handle: - * Handle to the pipe for the transfer. - * @buffer: Physical address of the data buffer in - * memory. Note that this is NOT A POINTER, but - * the full 64bit physical address of the - * buffer. This may be zero if buffer_length is - * zero. - * @buffer_length: - * Length of buffer in bytes. - * @callback: Function to call when this transaction - * completes. If the return value of this - * function isn't an error, then this function - * is guaranteed to be called when the - * transaction completes. If this parameter is - * NULL, then the generic callback registered - * through cvmx_usb_register_callback is - * called. If both are NULL, then there is no - * way to know when a transaction completes. - * @user_data: User supplied data returned when the - * callback is called. This is only used if - * callback in not NULL. - * - * Returns: A submitted transaction handle or negative on - * failure. Negative values are error codes. - */ -int cvmx_usb_submit_interrupt(struct cvmx_usb_state *state, int pipe_handle, - uint64_t buffer, int buffer_length, - cvmx_usb_callback_func_t callback, - void *user_data) -{ - int submit_handle; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - /* Pipe handle checking is done later in a common place */ - if (unlikely(!buffer)) - return -EINVAL; - if (unlikely(buffer_length < 0)) - return -EINVAL; - - submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle, - CVMX_USB_TRANSFER_INTERRUPT, - 0, /* flags */ - buffer, - buffer_length, - 0, /* control_header */ - 0, /* iso_start_frame */ - 0, /* iso_number_packets */ - NULL, /* iso_packets */ - callback, - user_data); - return submit_handle; -} - - -/** - * Call to submit a USB Control transfer to a pipe. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @pipe_handle: - * Handle to the pipe for the transfer. - * @control_header: - * USB 8 byte control header physical address. - * Note that this is NOT A POINTER, but the - * full 64bit physical address of the buffer. - * @buffer: Physical address of the data buffer in - * memory. Note that this is NOT A POINTER, but - * the full 64bit physical address of the - * buffer. This may be zero if buffer_length is - * zero. - * @buffer_length: - * Length of buffer in bytes. - * @callback: Function to call when this transaction - * completes. If the return value of this - * function isn't an error, then this function - * is guaranteed to be called when the - * transaction completes. If this parameter is - * NULL, then the generic callback registered - * through cvmx_usb_register_callback is - * called. If both are NULL, then there is no - * way to know when a transaction completes. - * @user_data: User supplied data returned when the - * callback is called. This is only used if - * callback in not NULL. - * - * Returns: A submitted transaction handle or negative on - * failure. Negative values are error codes. - */ -int cvmx_usb_submit_control(struct cvmx_usb_state *state, int pipe_handle, - uint64_t control_header, - uint64_t buffer, int buffer_length, - cvmx_usb_callback_func_t callback, - void *user_data) -{ - int submit_handle; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - union cvmx_usb_control_header *header = - cvmx_phys_to_ptr(control_header); - - /* Pipe handle checking is done later in a common place */ - if (unlikely(!control_header)) - return -EINVAL; - /* Some drivers send a buffer with a zero length. God only knows why */ - if (unlikely(buffer && (buffer_length < 0))) - return -EINVAL; - if (unlikely(!buffer && (buffer_length != 0))) - return -EINVAL; - if ((header->s.request_type & 0x80) == 0) - buffer_length = le16_to_cpu(header->s.length); - - submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle, - CVMX_USB_TRANSFER_CONTROL, - 0, /* flags */ - buffer, - buffer_length, - control_header, - 0, /* iso_start_frame */ - 0, /* iso_number_packets */ - NULL, /* iso_packets */ - callback, - user_data); - return submit_handle; -} - - -/** - * Call to submit a USB Isochronous transfer to a pipe. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @pipe_handle: - * Handle to the pipe for the transfer. - * @start_frame: - * Number of frames into the future to schedule - * this transaction. - * @flags: Flags to control the transfer. See - * enum cvmx_usb_isochronous_flags for the flag - * definitions. - * @number_packets: - * Number of sequential packets to transfer. - * "packets" is a pointer to an array of this - * many packet structures. - * @packets: Description of each transfer packet as - * defined by struct cvmx_usb_iso_packet. The array - * pointed to here must stay valid until the - * complete callback is called. - * @buffer: Physical address of the data buffer in - * memory. Note that this is NOT A POINTER, but - * the full 64bit physical address of the - * buffer. This may be zero if buffer_length is - * zero. - * @buffer_length: - * Length of buffer in bytes. - * @callback: Function to call when this transaction - * completes. If the return value of this - * function isn't an error, then this function - * is guaranteed to be called when the - * transaction completes. If this parameter is - * NULL, then the generic callback registered - * through cvmx_usb_register_callback is - * called. If both are NULL, then there is no - * way to know when a transaction completes. - * @user_data: User supplied data returned when the - * callback is called. This is only used if - * callback in not NULL. - * - * Returns: A submitted transaction handle or negative on - * failure. Negative values are error codes. - */ -int cvmx_usb_submit_isochronous(struct cvmx_usb_state *state, int pipe_handle, - int start_frame, int flags, - int number_packets, - struct cvmx_usb_iso_packet packets[], - uint64_t buffer, int buffer_length, - cvmx_usb_callback_func_t callback, - void *user_data) -{ - int submit_handle; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - /* Pipe handle checking is done later in a common place */ - if (unlikely(start_frame < 0)) - return -EINVAL; - if (unlikely(flags & ~(CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT | CVMX_USB_ISOCHRONOUS_FLAGS_ASAP))) - return -EINVAL; - if (unlikely(number_packets < 1)) - return -EINVAL; - if (unlikely(!packets)) - return -EINVAL; - if (unlikely(!buffer)) - return -EINVAL; - if (unlikely(buffer_length < 0)) - return -EINVAL; - - submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle, - CVMX_USB_TRANSFER_ISOCHRONOUS, - flags, - buffer, - buffer_length, - 0, /* control_header */ - start_frame, - number_packets, - packets, - callback, - user_data); - return submit_handle; -} - - -/** - * Cancel one outstanding request in a pipe. Canceling a request - * can fail if the transaction has already completed before cancel - * is called. Even after a successful cancel call, it may take - * a frame or two for the cvmx_usb_poll() function to call the - * associated callback. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @pipe_handle: - * Pipe handle to cancel requests in. - * @submit_handle: - * Handle to transaction to cancel, returned by the submit function. - * - * Returns: 0 or a negative error code. - */ -int cvmx_usb_cancel(struct cvmx_usb_state *state, int pipe_handle, int submit_handle) -{ - struct cvmx_usb_transaction *transaction; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle; - - if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES))) - return -EINVAL; - if (unlikely((submit_handle < 0) || (submit_handle >= MAX_TRANSACTIONS))) - return -EINVAL; - - /* Fail if the pipe isn't open */ - if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0)) - return -EINVAL; - - transaction = usb->transaction + submit_handle; - - /* Fail if this transaction already completed */ - if (unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0)) - return -EINVAL; - - /* - * If the transaction is the HEAD of the queue and scheduled. We need to - * treat it special - */ - if ((pipe->head == transaction) && - (pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED)) { - union cvmx_usbcx_hccharx usbc_hcchar; - - usb->pipe_for_channel[pipe->channel] = NULL; - pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED; - - CVMX_SYNCW; - - usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index)); - /* If the channel isn't enabled then the transaction already completed */ - if (usbc_hcchar.s.chena) { - usbc_hcchar.s.chdis = 1; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index), usbc_hcchar.u32); - } - } - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_CANCEL); - return 0; -} - - -/** - * Cancel all outstanding requests in a pipe. Logically all this - * does is call cvmx_usb_cancel() in a loop. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @pipe_handle: - * Pipe handle to cancel requests in. - * - * Returns: 0 or a negative error code. - */ -int cvmx_usb_cancel_all(struct cvmx_usb_state *state, int pipe_handle) -{ - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle; - - if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES))) - return -EINVAL; - - /* Fail if the pipe isn't open */ - if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0)) - return -EINVAL; - - /* Simply loop through and attempt to cancel each transaction */ - while (pipe->head) { - int result = cvmx_usb_cancel(state, pipe_handle, - __cvmx_usb_get_submit_handle(usb, pipe->head)); - if (unlikely(result != 0)) - return result; - } - return 0; -} - - -/** - * Close a pipe created with cvmx_usb_open_pipe(). - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @pipe_handle: - * Pipe handle to close. - * - * Returns: 0 or a negative error code. EBUSY is returned if the pipe has - * outstanding transfers. - */ -int cvmx_usb_close_pipe(struct cvmx_usb_state *state, int pipe_handle) -{ - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle; - - if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES))) - return -EINVAL; - - /* Fail if the pipe isn't open */ - if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0)) - return -EINVAL; - - /* Fail if the pipe has pending transactions */ - if (unlikely(pipe->head)) - return -EBUSY; - - pipe->flags = 0; - __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe); - __cvmx_usb_append_pipe(&usb->free_pipes, pipe); - - return 0; -} - - -/** - * Register a function to be called when various USB events occur. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * @reason: Which event to register for. - * @callback: Function to call when the event occurs. - * @user_data: User data parameter to the function. - * - * Returns: 0 or a negative error code. - */ -int cvmx_usb_register_callback(struct cvmx_usb_state *state, - enum cvmx_usb_callback reason, - cvmx_usb_callback_func_t callback, - void *user_data) -{ - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - if (unlikely(reason >= __CVMX_USB_CALLBACK_END)) - return -EINVAL; - if (unlikely(!callback)) - return -EINVAL; - - usb->callback[reason] = callback; - usb->callback_data[reason] = user_data; - - return 0; -} - - -/** - * Get the current USB protocol level frame number. The frame - * number is always in the range of 0-0x7ff. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * - * Returns: USB frame number - */ -int cvmx_usb_get_frame_number(struct cvmx_usb_state *state) -{ - int frame_number; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - union cvmx_usbcx_hfnum usbc_hfnum; - - usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index)); - frame_number = usbc_hfnum.s.frnum; - - return frame_number; -} - - -/** - * Poll a channel for status - * - * @usb: USB device - * @channel: Channel to poll - * - * Returns: Zero on success - */ -static int __cvmx_usb_poll_channel(struct cvmx_usb_internal_state *usb, int channel) -{ - union cvmx_usbcx_hcintx usbc_hcint; - union cvmx_usbcx_hctsizx usbc_hctsiz; - union cvmx_usbcx_hccharx usbc_hcchar; - struct cvmx_usb_pipe *pipe; - struct cvmx_usb_transaction *transaction; - int bytes_this_transfer; - int bytes_in_last_packet; - int packets_processed; - int buffer_space_left; - - /* Read the interrupt status bits for the channel */ - usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index)); - - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { - usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index)); - - if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) { - /* - * There seems to be a bug in CN31XX which can cause - * interrupt IN transfers to get stuck until we do a - * write of HCCHARX without changing things - */ - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32); - return 0; - } - - /* - * In non DMA mode the channels don't halt themselves. We need - * to manually disable channels that are left running - */ - if (!usbc_hcint.s.chhltd) { - if (usbc_hcchar.s.chena) { - union cvmx_usbcx_hcintmskx hcintmsk; - /* Disable all interrupts except CHHLTD */ - hcintmsk.u32 = 0; - hcintmsk.s.chhltdmsk = 1; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), hcintmsk.u32); - usbc_hcchar.s.chdis = 1; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32); - return 0; - } else if (usbc_hcint.s.xfercompl) { - /* Successful IN/OUT with transfer complete. Channel halt isn't needed */ - } else { - cvmx_dprintf("USB%d: Channel %d interrupt without halt\n", usb->index, channel); - return 0; - } - } - } else { - /* - * There is are no interrupts that we need to process when the - * channel is still running - */ - if (!usbc_hcint.s.chhltd) - return 0; - } - - /* Disable the channel interrupts now that it is done */ - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0); - usb->idle_hardware_channels |= (1<<channel); - - /* Make sure this channel is tied to a valid pipe */ - pipe = usb->pipe_for_channel[channel]; - CVMX_PREFETCH(pipe, 0); - CVMX_PREFETCH(pipe, 128); - if (!pipe) - return 0; - transaction = pipe->head; - CVMX_PREFETCH0(transaction); - - /* - * Disconnect this pipe from the HW channel. Later the schedule - * function will figure out which pipe needs to go - */ - usb->pipe_for_channel[channel] = NULL; - pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED; - - /* - * Read the channel config info so we can figure out how much data - * transfered - */ - usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index)); - usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index)); - - /* - * Calculating the number of bytes successfully transferred is dependent - * on the transfer direction - */ - packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt; - if (usbc_hcchar.s.epdir) { - /* - * IN transactions are easy. For every byte received the - * hardware decrements xfersize. All we need to do is subtract - * the current value of xfersize from its starting value and we - * know how many bytes were written to the buffer - */ - bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize; - } else { - /* - * OUT transaction don't decrement xfersize. Instead pktcnt is - * decremented on every successful packet send. The hardware - * does this when it receives an ACK, or NYET. If it doesn't - * receive one of these responses pktcnt doesn't change - */ - bytes_this_transfer = packets_processed * usbc_hcchar.s.mps; - /* - * The last packet may not be a full transfer if we didn't have - * enough data - */ - if (bytes_this_transfer > transaction->xfersize) - bytes_this_transfer = transaction->xfersize; - } - /* Figure out how many bytes were in the last packet of the transfer */ - if (packets_processed) - bytes_in_last_packet = bytes_this_transfer - (packets_processed-1) * usbc_hcchar.s.mps; - else - bytes_in_last_packet = bytes_this_transfer; - - /* - * As a special case, setup transactions output the setup header, not - * the user's data. For this reason we don't count setup data as bytes - * transferred - */ - if ((transaction->stage == CVMX_USB_STAGE_SETUP) || - (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE)) - bytes_this_transfer = 0; - - /* - * Add the bytes transferred to the running total. It is important that - * bytes_this_transfer doesn't count any data that needs to be - * retransmitted - */ - transaction->actual_bytes += bytes_this_transfer; - if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) - buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes; - else - buffer_space_left = transaction->buffer_length - transaction->actual_bytes; - - /* - * We need to remember the PID toggle state for the next transaction. - * The hardware already updated it for the next transaction - */ - pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0); - - /* - * For high speed bulk out, assume the next transaction will need to do - * a ping before proceeding. If this isn't true the ACK processing below - * will clear this flag - */ - if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) && - (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) && - (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT)) - pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING; - - if (usbc_hcint.s.stall) { - /* - * STALL as a response means this transaction cannot be - * completed because the device can't process transactions. Tell - * the user. Any data that was transferred will be counted on - * the actual bytes transferred - */ - pipe->pid_toggle = 0; - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL); - } else if (usbc_hcint.s.xacterr) { - /* - * We know at least one packet worked if we get a ACK or NAK. - * Reset the retry counter - */ - if (usbc_hcint.s.nak || usbc_hcint.s.ack) - transaction->retries = 0; - transaction->retries++; - if (transaction->retries > MAX_RETRIES) { - /* - * XactErr as a response means the device signaled - * something wrong with the transfer. For example, PID - * toggle errors cause these - */ - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR); - } else { - /* - * If this was a split then clear our split in progress - * marker - */ - if (usb->active_split == transaction) - usb->active_split = NULL; - /* - * Rewind to the beginning of the transaction by anding - * off the split complete bit - */ - transaction->stage &= ~1; - pipe->split_sc_frame = -1; - pipe->next_tx_frame += pipe->interval; - if (pipe->next_tx_frame < usb->frame_number) - pipe->next_tx_frame = usb->frame_number + pipe->interval - - (usb->frame_number - pipe->next_tx_frame) % pipe->interval; - } - } else if (usbc_hcint.s.bblerr) { - /* Babble Error (BblErr) */ - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_BABBLEERR); - } else if (usbc_hcint.s.datatglerr) { - /* We'll retry the exact same transaction again */ - transaction->retries++; - } else if (usbc_hcint.s.nyet) { - /* - * NYET as a response is only allowed in three cases: as a - * response to a ping, as a response to a split transaction, and - * as a response to a bulk out. The ping case is handled by - * hardware, so we only have splits and bulk out - */ - if (!__cvmx_usb_pipe_needs_split(usb, pipe)) { - transaction->retries = 0; - /* - * If there is more data to go then we need to try - * again. Otherwise this transaction is complete - */ - if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); - } else { - /* - * Split transactions retry the split complete 4 times - * then rewind to the start split and do the entire - * transactions again - */ - transaction->retries++; - if ((transaction->retries & 0x3) == 0) { - /* - * Rewind to the beginning of the transaction by - * anding off the split complete bit - */ - transaction->stage &= ~1; - pipe->split_sc_frame = -1; - } - } - } else if (usbc_hcint.s.ack) { - transaction->retries = 0; - /* - * The ACK bit can only be checked after the other error bits. - * This is because a multi packet transfer may succeed in a - * number of packets and then get a different response on the - * last packet. In this case both ACK and the last response bit - * will be set. If none of the other response bits is set, then - * the last packet must have been an ACK - * - * Since we got an ACK, we know we don't need to do a ping on - * this pipe - */ - pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_NEED_PING; - - switch (transaction->type) { - case CVMX_USB_TRANSFER_CONTROL: - switch (transaction->stage) { - case CVMX_USB_STAGE_NON_CONTROL: - case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE: - /* This should be impossible */ - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR); - break; - case CVMX_USB_STAGE_SETUP: - pipe->pid_toggle = 1; - if (__cvmx_usb_pipe_needs_split(usb, pipe)) - transaction->stage = CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE; - else { - union cvmx_usb_control_header *header = - cvmx_phys_to_ptr(transaction->control_header); - if (header->s.length) - transaction->stage = CVMX_USB_STAGE_DATA; - else - transaction->stage = CVMX_USB_STAGE_STATUS; - } - break; - case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE: - { - union cvmx_usb_control_header *header = - cvmx_phys_to_ptr(transaction->control_header); - if (header->s.length) - transaction->stage = CVMX_USB_STAGE_DATA; - else - transaction->stage = CVMX_USB_STAGE_STATUS; - } - break; - case CVMX_USB_STAGE_DATA: - if (__cvmx_usb_pipe_needs_split(usb, pipe)) { - transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE; - /* - * For setup OUT data that are splits, - * the hardware doesn't appear to count - * transferred data. Here we manually - * update the data transferred - */ - if (!usbc_hcchar.s.epdir) { - if (buffer_space_left < pipe->max_packet) - transaction->actual_bytes += buffer_space_left; - else - transaction->actual_bytes += pipe->max_packet; - } - } else if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) { - pipe->pid_toggle = 1; - transaction->stage = CVMX_USB_STAGE_STATUS; - } - break; - case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE: - if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) { - pipe->pid_toggle = 1; - transaction->stage = CVMX_USB_STAGE_STATUS; - } else { - transaction->stage = CVMX_USB_STAGE_DATA; - } - break; - case CVMX_USB_STAGE_STATUS: - if (__cvmx_usb_pipe_needs_split(usb, pipe)) - transaction->stage = CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE; - else - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); - break; - case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE: - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); - break; - } - break; - case CVMX_USB_TRANSFER_BULK: - case CVMX_USB_TRANSFER_INTERRUPT: - /* - * The only time a bulk transfer isn't complete when it - * finishes with an ACK is during a split transaction. - * For splits we need to continue the transfer if more - * data is needed - */ - if (__cvmx_usb_pipe_needs_split(usb, pipe)) { - if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL) - transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE; - else { - if (buffer_space_left && (bytes_in_last_packet == pipe->max_packet)) - transaction->stage = CVMX_USB_STAGE_NON_CONTROL; - else { - if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT) - pipe->next_tx_frame += pipe->interval; - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); - } - } - } else { - if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) && - (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) && - (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) && - (usbc_hcint.s.nak)) - pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING; - if (!buffer_space_left || (bytes_in_last_packet < pipe->max_packet)) { - if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT) - pipe->next_tx_frame += pipe->interval; - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); - } - } - break; - case CVMX_USB_TRANSFER_ISOCHRONOUS: - if (__cvmx_usb_pipe_needs_split(usb, pipe)) { - /* - * ISOCHRONOUS OUT splits don't require a - * complete split stage. Instead they use a - * sequence of begin OUT splits to transfer the - * data 188 bytes at a time. Once the transfer - * is complete, the pipe sleeps until the next - * schedule interval - */ - if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) { - /* - * If no space left or this wasn't a max - * size packet then this transfer is - * complete. Otherwise start it again to - * send the next 188 bytes - */ - if (!buffer_space_left || (bytes_this_transfer < 188)) { - pipe->next_tx_frame += pipe->interval; - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); - } - } else { - if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) { - /* - * We are in the incoming data - * phase. Keep getting data - * until we run out of space or - * get a small packet - */ - if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) { - pipe->next_tx_frame += pipe->interval; - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); - } - } else - transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE; - } - } else { - pipe->next_tx_frame += pipe->interval; - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); - } - break; - } - } else if (usbc_hcint.s.nak) { - /* If this was a split then clear our split in progress marker */ - if (usb->active_split == transaction) - usb->active_split = NULL; - /* - * NAK as a response means the device couldn't accept the - * transaction, but it should be retried in the future. Rewind - * to the beginning of the transaction by anding off the split - * complete bit. Retry in the next interval - */ - transaction->retries = 0; - transaction->stage &= ~1; - pipe->next_tx_frame += pipe->interval; - if (pipe->next_tx_frame < usb->frame_number) - pipe->next_tx_frame = usb->frame_number + pipe->interval - - (usb->frame_number - pipe->next_tx_frame) % pipe->interval; - } else { - struct cvmx_usb_port_status port; - port = cvmx_usb_get_status((struct cvmx_usb_state *)usb); - if (port.port_enabled) { - /* We'll retry the exact same transaction again */ - transaction->retries++; - } else { - /* - * We get channel halted interrupts with no result bits - * sets when the cable is unplugged - */ - __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR); - } - } - return 0; -} - - -/** - * Poll the USB block for status and call all needed callback - * handlers. This function is meant to be called in the interrupt - * handler for the USB controller. It can also be called - * periodically in a loop for non-interrupt based operation. - * - * @state: USB device state populated by - * cvmx_usb_initialize(). - * - * Returns: 0 or a negative error code. - */ -int cvmx_usb_poll(struct cvmx_usb_state *state) -{ - union cvmx_usbcx_hfnum usbc_hfnum; - union cvmx_usbcx_gintsts usbc_gintsts; - struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state; - - CVMX_PREFETCH(usb, 0); - CVMX_PREFETCH(usb, 1*128); - CVMX_PREFETCH(usb, 2*128); - CVMX_PREFETCH(usb, 3*128); - CVMX_PREFETCH(usb, 4*128); - - /* Update the frame counter */ - usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index)); - if ((usb->frame_number&0x3fff) > usbc_hfnum.s.frnum) - usb->frame_number += 0x4000; - usb->frame_number &= ~0x3fffull; - usb->frame_number |= usbc_hfnum.s.frnum; - - /* Read the pending interrupts */ - usbc_gintsts.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index)); - - /* Clear the interrupts now that we know about them */ - __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32); - - if (usbc_gintsts.s.rxflvl) { - /* - * RxFIFO Non-Empty (RxFLvl) - * Indicates that there is at least one packet pending to be - * read from the RxFIFO. - * - * In DMA mode this is handled by hardware - */ - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) - __cvmx_usb_poll_rx_fifo(usb); - } - if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) { - /* Fill the Tx FIFOs when not in DMA mode */ - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) - __cvmx_usb_poll_tx_fifo(usb); - } - if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) { - union cvmx_usbcx_hprt usbc_hprt; - /* - * Disconnect Detected Interrupt (DisconnInt) - * Asserted when a device disconnect is detected. - * - * Host Port Interrupt (PrtInt) - * The core sets this bit to indicate a change in port status of - * one of the O2P USB core ports in Host mode. The application - * must read the Host Port Control and Status (HPRT) register to - * determine the exact event that caused this interrupt. The - * application must clear the appropriate status bit in the Host - * Port Control and Status register to clear this bit. - * - * Call the user's port callback - */ - __cvmx_usb_perform_callback(usb, NULL, NULL, - CVMX_USB_CALLBACK_PORT_CHANGED, - CVMX_USB_COMPLETE_SUCCESS); - /* Clear the port change bits */ - usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); - usbc_hprt.s.prtena = 0; - __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32); - } - if (usbc_gintsts.s.hchint) { - /* - * Host Channels Interrupt (HChInt) - * The core sets this bit to indicate that an interrupt is - * pending on one of the channels of the core (in Host mode). - * The application must read the Host All Channels Interrupt - * (HAINT) register to determine the exact number of the channel - * on which the interrupt occurred, and then read the - * corresponding Host Channel-n Interrupt (HCINTn) register to - * determine the exact cause of the interrupt. The application - * must clear the appropriate status bit in the HCINTn register - * to clear this bit. - */ - union cvmx_usbcx_haint usbc_haint; - usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index)); - while (usbc_haint.u32) { - int channel; - CVMX_CLZ(channel, usbc_haint.u32); - channel = 31 - channel; - __cvmx_usb_poll_channel(usb, channel); - usbc_haint.u32 ^= 1<<channel; - } - } - - __cvmx_usb_schedule(usb, usbc_gintsts.s.sof); - - return 0; -} diff --git a/drivers/staging/octeon-usb/cvmx-usb.h b/drivers/staging/octeon-usb/cvmx-usb.h deleted file mode 100644 index 8bf36966ef15..000000000000 --- a/drivers/staging/octeon-usb/cvmx-usb.h +++ /dev/null @@ -1,542 +0,0 @@ -/***********************license start*************** - * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights - * reserved. - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - - * * Neither the name of Cavium Networks nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written - * permission. - - * This Software, including technical data, may be subject to U.S. export control - * laws, including the U.S. Export Administration Act and its associated - * regulations, and may be subject to export or import regulations in other - * countries. - - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR - * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO - * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR - * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM - * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, - * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF - * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR - * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR - * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. - ***********************license end**************************************/ - - -/** - * "cvmx-usb.h" defines a set of low level USB functions to help - * developers create Octeon USB drivers for various operating - * systems. These functions provide a generic API to the Octeon - * USB blocks, hiding the internal hardware specific - * operations. - * - * At a high level the device driver needs to: - * - * - Call cvmx_usb_get_num_ports() to get the number of - * supported ports. - * - Call cvmx_usb_initialize() for each Octeon USB port. - * - Enable the port using cvmx_usb_enable(). - * - Either periodically, or in an interrupt handler, call - * cvmx_usb_poll() to service USB events. - * - Manage pipes using cvmx_usb_open_pipe() and - * cvmx_usb_close_pipe(). - * - Manage transfers using cvmx_usb_submit_*() and - * cvmx_usb_cancel*(). - * - Shutdown USB on unload using cvmx_usb_shutdown(). - * - * To monitor USB status changes, the device driver must use - * cvmx_usb_register_callback() to register for events that it - * is interested in. Below are a few hints on successfully - * implementing a driver on top of this API. - * - * == Initialization == - * - * When a driver is first loaded, it is normally not necessary - * to bring up the USB port completely. Most operating systems - * expect to initialize and enable the port in two independent - * steps. Normally an operating system will probe hardware, - * initialize anything found, and then enable the hardware. - * - * In the probe phase you should: - * - Use cvmx_usb_get_num_ports() to determine the number of - * USB port to be supported. - * - Allocate space for a struct cvmx_usb_state for each - * port. - * - Tell the operating system about each port - * - * In the initialization phase you should: - * - Use cvmx_usb_initialize() on each port. - * - Do not call cvmx_usb_enable(). This leaves the USB port in - * the disabled state until the operating system is ready. - * - * Finally, in the enable phase you should: - * - Call cvmx_usb_enable() on the appropriate port. - * - Note that some operating system use a RESET instead of an - * enable call. To implement RESET, you should call - * cvmx_usb_disable() followed by cvmx_usb_enable(). - * - * == Locking == - * - * All of the functions in the cvmx-usb API assume exclusive - * access to the USB hardware and internal data structures. This - * means that the driver must provide locking as necessary. - * - * In the single CPU state it is normally enough to disable - * interrupts before every call to cvmx_usb*() and enable them - * again after the call is complete. Keep in mind that it is - * very common for the callback handlers to make additional - * calls into cvmx-usb, so the disable/enable must be protected - * against recursion. As an example, the Linux kernel - * local_irq_save() and local_irq_restore() are perfect for this - * in the non SMP case. - * - * In the SMP case, locking is more complicated. For SMP you not - * only need to disable interrupts on the local core, but also - * take a lock to make sure that another core cannot call - * cvmx-usb. - * - * == Port callback == - * - * The port callback prototype needs to look as follows: - * - * void port_callback(struct cvmx_usb_state *usb, - * enum cvmx_usb_callback reason, - * enum cvmx_usb_complete status, - * int pipe_handle, - * int submit_handle, - * int bytes_transferred, - * void *user_data); - * - "usb" is the struct cvmx_usb_state for the port. - * - "reason" will always be CVMX_USB_CALLBACK_PORT_CHANGED. - * - "status" will always be CVMX_USB_COMPLETE_SUCCESS. - * - "pipe_handle" will always be -1. - * - "submit_handle" will always be -1. - * - "bytes_transferred" will always be 0. - * - "user_data" is the void pointer originally passed along - * with the callback. Use this for any state information you - * need. - * - * The port callback will be called whenever the user plugs / - * unplugs a device from the port. It will not be called when a - * device is plugged / unplugged from a hub connected to the - * root port. Normally all the callback needs to do is tell the - * operating system to poll the root hub for status. Under - * Linux, this is performed by calling usb_hcd_poll_rh_status(). - * In the Linux driver we use "user_data". to pass around the - * Linux "hcd" structure. Once the port callback completes, - * Linux automatically calls octeon_usb_hub_status_data() which - * uses cvmx_usb_get_status() to determine the root port status. - * - * == Complete callback == - * - * The completion callback prototype needs to look as follows: - * - * void complete_callback(struct cvmx_usb_state *usb, - * enum cvmx_usb_callback reason, - * enum cvmx_usb_complete status, - * int pipe_handle, - * int submit_handle, - * int bytes_transferred, - * void *user_data); - * - "usb" is the struct cvmx_usb_state for the port. - * - "reason" will always be CVMX_USB_CALLBACK_TRANSFER_COMPLETE. - * - "status" will be one of the cvmx_usb_complete enumerations. - * - "pipe_handle" is the handle to the pipe the transaction - * was originally submitted on. - * - "submit_handle" is the handle returned by the original - * cvmx_usb_submit_* call. - * - "bytes_transferred" is the number of bytes successfully - * transferred in the transaction. This will be zero on most - * error conditions. - * - "user_data" is the void pointer originally passed along - * with the callback. Use this for any state information you - * need. For example, the Linux "urb" is stored in here in the - * Linux driver. - * - * In general your callback handler should use "status" and - * "bytes_transferred" to tell the operating system the how the - * transaction completed. Normally the pipe is not changed in - * this callback. - * - * == Canceling transactions == - * - * When a transaction is cancelled using cvmx_usb_cancel*(), the - * actual length of time until the complete callback is called - * can vary greatly. It may be called before cvmx_usb_cancel*() - * returns, or it may be called a number of usb frames in the - * future once the hardware frees the transaction. In either of - * these cases, the complete handler will receive - * CVMX_USB_COMPLETE_CANCEL. - * - * == Handling pipes == - * - * USB "pipes" is a software construct created by this API to - * enable the ordering of usb transactions to a device endpoint. - * Octeon's underlying hardware doesn't have any concept - * equivalent to "pipes". The hardware instead has eight - * channels that can be used simultaneously to have up to eight - * transaction in process at the same time. In order to maintain - * ordering in a pipe, the transactions for a pipe will only be - * active in one hardware channel at a time. From an API user's - * perspective, this doesn't matter but it can be helpful to - * keep this in mind when you are probing hardware while - * debugging. - * - * Also keep in mind that usb transactions contain state - * information about the previous transaction to the same - * endpoint. Each transaction has a PID toggle that changes 0/1 - * between each sub packet. This is maintained in the pipe data - * structures. For this reason, you generally cannot create and - * destroy a pipe for every transaction. A sequence of - * transaction to the same endpoint must use the same pipe. - * - * == Root Hub == - * - * Some operating systems view the usb root port as a normal usb - * hub. These systems attempt to control the root hub with - * messages similar to the usb 2.0 spec for hub control and - * status. For these systems it may be necessary to write - * function to decode standard usb control messages into - * equivalent cvmx-usb API calls. - * - * == Interrupts == - * - * If you plan on using usb interrupts, cvmx_usb_poll() must be - * called on every usb interrupt. It will read the usb state, - * call any needed callbacks, and schedule transactions as - * needed. Your device driver needs only to hookup an interrupt - * handler and call cvmx_usb_poll(). Octeon's usb port 0 causes - * CIU bit CIU_INT*_SUM0[USB] to be set (bit 56). For port 1, - * CIU bit CIU_INT_SUM1[USB1] is set (bit 17). How these bits - * are turned into interrupt numbers is operating system - * specific. For Linux, there are the convenient defines - * OCTEON_IRQ_USB0 and OCTEON_IRQ_USB1 for the IRQ numbers. - * - * If you aren't using interrupts, simple call cvmx_usb_poll() - * in your main processing loop. - */ - -#ifndef __CVMX_USB_H__ -#define __CVMX_USB_H__ - -/** - * enum cvmx_usb_speed - the possible USB device speeds - * - * @CVMX_USB_SPEED_HIGH: Device is operation at 480Mbps - * @CVMX_USB_SPEED_FULL: Device is operation at 12Mbps - * @CVMX_USB_SPEED_LOW: Device is operation at 1.5Mbps - */ -enum cvmx_usb_speed { - CVMX_USB_SPEED_HIGH = 0, - CVMX_USB_SPEED_FULL = 1, - CVMX_USB_SPEED_LOW = 2, -}; - -/** - * enum cvmx_usb_transfer - the possible USB transfer types - * - * @CVMX_USB_TRANSFER_CONTROL: USB transfer type control for hub and status - * transfers - * @CVMX_USB_TRANSFER_ISOCHRONOUS: USB transfer type isochronous for low - * priority periodic transfers - * @CVMX_USB_TRANSFER_BULK: USB transfer type bulk for large low priority - * transfers - * @CVMX_USB_TRANSFER_INTERRUPT: USB transfer type interrupt for high priority - * periodic transfers - */ -enum cvmx_usb_transfer { - CVMX_USB_TRANSFER_CONTROL = 0, - CVMX_USB_TRANSFER_ISOCHRONOUS = 1, - CVMX_USB_TRANSFER_BULK = 2, - CVMX_USB_TRANSFER_INTERRUPT = 3, -}; - -/** - * enum cvmx_usb_direction - the transfer directions - * - * @CVMX_USB_DIRECTION_OUT: Data is transferring from Octeon to the device/host - * @CVMX_USB_DIRECTION_IN: Data is transferring from the device/host to Octeon - */ -enum cvmx_usb_direction { - CVMX_USB_DIRECTION_OUT, - CVMX_USB_DIRECTION_IN, -}; - -/** - * enum cvmx_usb_complete - possible callback function status codes - * - * @CVMX_USB_COMPLETE_SUCCESS: The transaction / operation finished without - * any errors - * @CVMX_USB_COMPLETE_SHORT: FIXME: This is currently not implemented - * @CVMX_USB_COMPLETE_CANCEL: The transaction was canceled while in flight by - * a user call to cvmx_usb_cancel - * @CVMX_USB_COMPLETE_ERROR: The transaction aborted with an unexpected - * error status - * @CVMX_USB_COMPLETE_STALL: The transaction received a USB STALL response - * from the device - * @CVMX_USB_COMPLETE_XACTERR: The transaction failed with an error from the - * device even after a number of retries - * @CVMX_USB_COMPLETE_DATATGLERR: The transaction failed with a data toggle - * error even after a number of retries - * @CVMX_USB_COMPLETE_BABBLEERR: The transaction failed with a babble error - * @CVMX_USB_COMPLETE_FRAMEERR: The transaction failed with a frame error - * even after a number of retries - */ -enum cvmx_usb_complete { - CVMX_USB_COMPLETE_SUCCESS, - CVMX_USB_COMPLETE_SHORT, - CVMX_USB_COMPLETE_CANCEL, - CVMX_USB_COMPLETE_ERROR, - CVMX_USB_COMPLETE_STALL, - CVMX_USB_COMPLETE_XACTERR, - CVMX_USB_COMPLETE_DATATGLERR, - CVMX_USB_COMPLETE_BABBLEERR, - CVMX_USB_COMPLETE_FRAMEERR, -}; - -/** - * struct cvmx_usb_port_status - the USB port status information - * - * @port_enabled: 1 = Usb port is enabled, 0 = disabled - * @port_over_current: 1 = Over current detected, 0 = Over current not - * detected. Octeon doesn't support over current detection. - * @port_powered: 1 = Port power is being supplied to the device, 0 = - * power is off. Octeon doesn't support turning port power - * off. - * @port_speed: Current port speed. - * @connected: 1 = A device is connected to the port, 0 = No device is - * connected. - * @connect_change: 1 = Device connected state changed since the last set - * status call. - */ -struct cvmx_usb_port_status { - uint32_t reserved : 25; - uint32_t port_enabled : 1; - uint32_t port_over_current : 1; - uint32_t port_powered : 1; - enum cvmx_usb_speed port_speed : 2; - uint32_t connected : 1; - uint32_t connect_change : 1; -}; - -/** - * union cvmx_usb_control_header - the structure of a Control packet header - * - * @s.request_type: Bit 7 tells the direction: 1=IN, 0=OUT - * @s.request The standard usb request to make - * @s.value Value parameter for the request in little endian format - * @s.index Index for the request in little endian format - * @s.length Length of the data associated with this request in - * little endian format - */ -union cvmx_usb_control_header { - uint64_t u64; - struct { - uint64_t request_type : 8; - uint64_t request : 8; - uint64_t value : 16; - uint64_t index : 16; - uint64_t length : 16; - } s; -}; - -/** - * struct cvmx_usb_iso_packet - descriptor for Isochronous packets - * - * @offset: This is the offset in bytes into the main buffer where this data - * is stored. - * @length: This is the length in bytes of the data. - * @status: This is the status of this individual packet transfer. - */ -struct cvmx_usb_iso_packet { - int offset; - int length; - enum cvmx_usb_complete status; -}; - -/** - * enum cvmx_usb_callback - possible callback reasons for the USB API - * - * @CVMX_USB_CALLBACK_TRANSFER_COMPLETE: A callback of this type is called when - * a submitted transfer completes. The - * completion callback will be called even - * if the transfer fails or is canceled. - * The status parameter will contain - * details of why he callback was called. - * @CVMX_USB_CALLBACK_PORT_CHANGED: The status of the port changed. For - * example, someone may have plugged a - * device in. The status parameter - * contains CVMX_USB_COMPLETE_SUCCESS. Use - * cvmx_usb_get_status() to get the new - * port status. - * @__CVMX_USB_CALLBACK_END: Do not use. Used internally for array - * bounds. - */ -enum cvmx_usb_callback { - CVMX_USB_CALLBACK_TRANSFER_COMPLETE, - CVMX_USB_CALLBACK_PORT_CHANGED, - __CVMX_USB_CALLBACK_END -}; - -/** - * USB state internal data. The contents of this structure - * may change in future SDKs. No data in it should be referenced - * by user's of this API. - */ -struct cvmx_usb_state { - char data[65536]; -}; - -/** - * USB callback functions are always of the following type. - * The parameters are as follows: - * - state = USB device state populated by - * cvmx_usb_initialize(). - * - reason = The enum cvmx_usb_callback used to register - * the callback. - * - status = The enum cvmx_usb_complete representing the - * status code of a transaction. - * - pipe_handle = The Pipe that caused this callback, or - * -1 if this callback wasn't associated with a pipe. - * - submit_handle = Transfer submit handle causing this - * callback, or -1 if this callback wasn't associated - * with a transfer. - * - Actual number of bytes transfer. - * - user_data = The user pointer supplied to the - * function cvmx_usb_submit() or - * cvmx_usb_register_callback() */ -typedef void (*cvmx_usb_callback_func_t)(struct cvmx_usb_state *state, - enum cvmx_usb_callback reason, - enum cvmx_usb_complete status, - int pipe_handle, int submit_handle, - int bytes_transferred, void *user_data); - -/** - * enum cvmx_usb_initialize_flags - flags to pass the initialization function - * - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI: The USB port uses a 12MHz crystal - * as clock source at USB_XO and - * USB_XI. - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND: The USB port uses 12/24/48MHz 2.5V - * board clock source at USB_XO. - * USB_XI should be tied to GND. - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO: Automatically determine clock type - * based on function in - * cvmx-helper-board.c. - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK: Mask for clock speed field - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ: Speed of reference clock or - * crystal - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ: Speed of reference clock - * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ: Speed of reference clock - * @CVMX_USB_INITIALIZE_FLAGS_NO_DMA: Disable DMA and used polled IO for - * data transfer use for the USB - */ -enum cvmx_usb_initialize_flags { - CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI = 1 << 0, - CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND = 1 << 1, - CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO = 0, - CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK = 3 << 3, - CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ = 1 << 3, - CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ = 2 << 3, - CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ = 3 << 3, - /* Bits 3-4 used to encode the clock frequency */ - CVMX_USB_INITIALIZE_FLAGS_NO_DMA = 1 << 5, -}; - -/** - * enum cvmx_usb_pipe_flags - flags for passing when a pipe is created. - * Currently no flags need to be passed. - * - * @__CVMX_USB_PIPE_FLAGS_OPEN: Used internally to determine if a pipe is - * open. Do not use. - * @__CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is - * actively using hardware. Do not use. - * @__CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high - * speed pipe is in the ping state. Do not - * use. - */ -enum cvmx_usb_pipe_flags { - __CVMX_USB_PIPE_FLAGS_OPEN = 1 << 16, - __CVMX_USB_PIPE_FLAGS_SCHEDULED = 1 << 17, - __CVMX_USB_PIPE_FLAGS_NEED_PING = 1 << 18, -}; - -extern int cvmx_usb_get_num_ports(void); -extern int cvmx_usb_initialize(struct cvmx_usb_state *state, int usb_port_number, - enum cvmx_usb_initialize_flags flags); -extern int cvmx_usb_shutdown(struct cvmx_usb_state *state); -extern int cvmx_usb_enable(struct cvmx_usb_state *state); -extern int cvmx_usb_disable(struct cvmx_usb_state *state); -extern struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *state); -extern void cvmx_usb_set_status(struct cvmx_usb_state *state, struct cvmx_usb_port_status port_status); -extern int cvmx_usb_open_pipe(struct cvmx_usb_state *state, - enum cvmx_usb_pipe_flags flags, - int device_addr, int endpoint_num, - enum cvmx_usb_speed device_speed, int max_packet, - enum cvmx_usb_transfer transfer_type, - enum cvmx_usb_direction transfer_dir, int interval, - int multi_count, int hub_device_addr, - int hub_port); -extern int cvmx_usb_submit_bulk(struct cvmx_usb_state *state, int pipe_handle, - uint64_t buffer, int buffer_length, - cvmx_usb_callback_func_t callback, - void *user_data); -extern int cvmx_usb_submit_interrupt(struct cvmx_usb_state *state, int pipe_handle, - uint64_t buffer, int buffer_length, - cvmx_usb_callback_func_t callback, - void *user_data); -extern int cvmx_usb_submit_control(struct cvmx_usb_state *state, int pipe_handle, - uint64_t control_header, - uint64_t buffer, int buffer_length, - cvmx_usb_callback_func_t callback, - void *user_data); - -/** - * enum cvmx_usb_isochronous_flags - flags to pass the - * cvmx_usb_submit_isochronous() function. - * - * @CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT: Do not return an error if a transfer - * is less than the maximum packet size - * of the device. - * @CVMX_USB_ISOCHRONOUS_FLAGS_ASAP: Schedule the transaction as soon as - * possible. - */ -enum cvmx_usb_isochronous_flags { - CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT = 1 << 0, - CVMX_USB_ISOCHRONOUS_FLAGS_ASAP = 1 << 1, -}; - -extern int cvmx_usb_submit_isochronous(struct cvmx_usb_state *state, int pipe_handle, - int start_frame, int flags, - int number_packets, - struct cvmx_usb_iso_packet packets[], - uint64_t buffer, int buffer_length, - cvmx_usb_callback_func_t callback, - void *user_data); -extern int cvmx_usb_cancel(struct cvmx_usb_state *state, int pipe_handle, - int submit_handle); -extern int cvmx_usb_cancel_all(struct cvmx_usb_state *state, int pipe_handle); -extern int cvmx_usb_close_pipe(struct cvmx_usb_state *state, int pipe_handle); -extern int cvmx_usb_register_callback(struct cvmx_usb_state *state, - enum cvmx_usb_callback reason, - cvmx_usb_callback_func_t callback, - void *user_data); -extern int cvmx_usb_get_frame_number(struct cvmx_usb_state *state); -extern int cvmx_usb_poll(struct cvmx_usb_state *state); - -#endif /* __CVMX_USB_H__ */ diff --git a/drivers/staging/octeon-usb/cvmx-usbnx-defs.h b/drivers/staging/octeon-usb/cvmx-usbnx-defs.h deleted file mode 100644 index e06aafa5726a..000000000000 --- a/drivers/staging/octeon-usb/cvmx-usbnx-defs.h +++ /dev/null @@ -1,885 +0,0 @@ -/***********************license start*************** - * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights - * reserved. - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - - * * Neither the name of Cavium Networks nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written - * permission. - - * This Software, including technical data, may be subject to U.S. export - * control laws, including the U.S. Export Administration Act and its associated - * regulations, and may be subject to export or import regulations in other - * countries. - - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR - * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO - * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION - * OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM - * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, - * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF - * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR - * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR - * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. - ***********************license end**************************************/ - - -/** - * cvmx-usbnx-defs.h - * - * Configuration and status register (CSR) type definitions for - * Octeon usbnx. - * - */ -#ifndef __CVMX_USBNX_TYPEDEFS_H__ -#define __CVMX_USBNX_TYPEDEFS_H__ - -#define CVMX_USBNXBID1(bid) (((bid) & 1) * 0x10000000ull) -#define CVMX_USBNXBID2(bid) (((bid) & 1) * 0x100000000000ull) - -#define CVMX_USBNXREG1(reg, bid) \ - (CVMX_ADD_IO_SEG(0x0001180068000000ull | reg) + CVMX_USBNXBID1(bid)) -#define CVMX_USBNXREG2(reg, bid) \ - (CVMX_ADD_IO_SEG(0x00016F0000000000ull | reg) + CVMX_USBNXBID2(bid)) - -#define CVMX_USBNX_CLK_CTL(bid) CVMX_USBNXREG1(0x10, bid) -#define CVMX_USBNX_DMA0_INB_CHN0(bid) CVMX_USBNXREG2(0x818, bid) -#define CVMX_USBNX_DMA0_OUTB_CHN0(bid) CVMX_USBNXREG2(0x858, bid) -#define CVMX_USBNX_USBP_CTL_STATUS(bid) CVMX_USBNXREG1(0x18, bid) - -/** - * cvmx_usbn#_clk_ctl - * - * USBN_CLK_CTL = USBN's Clock Control - * - * This register is used to control the frequency of the hclk and the - * hreset and phy_rst signals. - */ -union cvmx_usbnx_clk_ctl { - uint64_t u64; - /** - * struct cvmx_usbnx_clk_ctl_s - * @divide2: The 'hclk' used by the USB subsystem is derived - * from the eclk. - * Also see the field DIVIDE. DIVIDE2<1> must currently - * be zero because it is not implemented, so the maximum - * ratio of eclk/hclk is currently 16. - * The actual divide number for hclk is: - * (DIVIDE2 + 1) * (DIVIDE + 1) - * @hclk_rst: When this field is '0' the HCLK-DIVIDER used to - * generate the hclk in the USB Subsystem is held - * in reset. This bit must be set to '0' before - * changing the value os DIVIDE in this register. - * The reset to the HCLK_DIVIDERis also asserted - * when core reset is asserted. - * @p_x_on: Force USB-PHY on during suspend. - * '1' USB-PHY XO block is powered-down during - * suspend. - * '0' USB-PHY XO block is powered-up during - * suspend. - * The value of this field must be set while POR is - * active. - * @p_com_on: '0' Force USB-PHY XO Bias, Bandgap and PLL to - * remain powered in Suspend Mode. - * '1' The USB-PHY XO Bias, Bandgap and PLL are - * powered down in suspend mode. - * The value of this field must be set while POR is - * active. - * @p_c_sel: Phy clock speed select. - * Selects the reference clock / crystal frequency. - * '11': Reserved - * '10': 48 MHz (reserved when a crystal is used) - * '01': 24 MHz (reserved when a crystal is used) - * '00': 12 MHz - * The value of this field must be set while POR is - * active. - * NOTE: if a crystal is used as a reference clock, - * this field must be set to 12 MHz. - * @cdiv_byp: Used to enable the bypass input to the USB_CLK_DIV. - * @sd_mode: Scaledown mode for the USBC. Control timing events - * in the USBC, for normal operation this must be '0'. - * @s_bist: Starts bist on the hclk memories, during the '0' - * to '1' transition. - * @por: Power On Reset for the PHY. - * Resets all the PHYS registers and state machines. - * @enable: When '1' allows the generation of the hclk. When - * '0' the hclk will not be generated. SEE DIVIDE - * field of this register. - * @prst: When this field is '0' the reset associated with - * the phy_clk functionality in the USB Subsystem is - * help in reset. This bit should not be set to '1' - * until the time it takes 6 clocks (hclk or phy_clk, - * whichever is slower) has passed. Under normal - * operation once this bit is set to '1' it should not - * be set to '0'. - * @hrst: When this field is '0' the reset associated with - * the hclk functioanlity in the USB Subsystem is - * held in reset.This bit should not be set to '1' - * until 12ms after phy_clk is stable. Under normal - * operation, once this bit is set to '1' it should - * not be set to '0'. - * @divide: The frequency of 'hclk' used by the USB subsystem - * is the eclk frequency divided by the value of - * (DIVIDE2 + 1) * (DIVIDE + 1), also see the field - * DIVIDE2 of this register. - * The hclk frequency should be less than 125Mhz. - * After writing a value to this field the SW should - * read the field for the value written. - * The ENABLE field of this register should not be set - * until AFTER this field is set and then read. - */ - struct cvmx_usbnx_clk_ctl_s { - uint64_t reserved_20_63 : 44; - uint64_t divide2 : 2; - uint64_t hclk_rst : 1; - uint64_t p_x_on : 1; - uint64_t reserved_14_15 : 2; - uint64_t p_com_on : 1; - uint64_t p_c_sel : 2; - uint64_t cdiv_byp : 1; - uint64_t sd_mode : 2; - uint64_t s_bist : 1; - uint64_t por : 1; - uint64_t enable : 1; - uint64_t prst : 1; - uint64_t hrst : 1; - uint64_t divide : 3; - } s; - /** - * struct cvmx_usbnx_clk_ctl_cn30xx - * @hclk_rst: When this field is '0' the HCLK-DIVIDER used to - * generate the hclk in the USB Subsystem is held - * in reset. This bit must be set to '0' before - * changing the value os DIVIDE in this register. - * The reset to the HCLK_DIVIDERis also asserted - * when core reset is asserted. - * @p_x_on: Force USB-PHY on during suspend. - * '1' USB-PHY XO block is powered-down during - * suspend. - * '0' USB-PHY XO block is powered-up during - * suspend. - * The value of this field must be set while POR is - * active. - * @p_rclk: Phy refrence clock enable. - * '1' The PHY PLL uses the XO block output as a - * reference. - * '0' Reserved. - * @p_xenbn: Phy external clock enable. - * '1' The XO block uses the clock from a crystal. - * '0' The XO block uses an external clock supplied - * on the XO pin. USB_XI should be tied to - * ground for this usage. - * @p_com_on: '0' Force USB-PHY XO Bias, Bandgap and PLL to - * remain powered in Suspend Mode. - * '1' The USB-PHY XO Bias, Bandgap and PLL are - * powered down in suspend mode. - * The value of this field must be set while POR is - * active. - * @p_c_sel: Phy clock speed select. - * Selects the reference clock / crystal frequency. - * '11': Reserved - * '10': 48 MHz - * '01': 24 MHz - * '00': 12 MHz - * The value of this field must be set while POR is - * active. - * @cdiv_byp: Used to enable the bypass input to the USB_CLK_DIV. - * @sd_mode: Scaledown mode for the USBC. Control timing events - * in the USBC, for normal operation this must be '0'. - * @s_bist: Starts bist on the hclk memories, during the '0' - * to '1' transition. - * @por: Power On Reset for the PHY. - * Resets all the PHYS registers and state machines. - * @enable: When '1' allows the generation of the hclk. When - * '0' the hclk will not be generated. - * @prst: When this field is '0' the reset associated with - * the phy_clk functionality in the USB Subsystem is - * help in reset. This bit should not be set to '1' - * until the time it takes 6 clocks (hclk or phy_clk, - * whichever is slower) has passed. Under normal - * operation once this bit is set to '1' it should not - * be set to '0'. - * @hrst: When this field is '0' the reset associated with - * the hclk functioanlity in the USB Subsystem is - * held in reset.This bit should not be set to '1' - * until 12ms after phy_clk is stable. Under normal - * operation, once this bit is set to '1' it should - * not be set to '0'. - * @divide: The 'hclk' used by the USB subsystem is derived - * from the eclk. The eclk will be divided by the - * value of this field +1 to determine the hclk - * frequency. (Also see HRST of this register). - * The hclk frequency must be less than 125 MHz. - */ - struct cvmx_usbnx_clk_ctl_cn30xx { - uint64_t reserved_18_63 : 46; - uint64_t hclk_rst : 1; - uint64_t p_x_on : 1; - uint64_t p_rclk : 1; - uint64_t p_xenbn : 1; - uint64_t p_com_on : 1; - uint64_t p_c_sel : 2; - uint64_t cdiv_byp : 1; - uint64_t sd_mode : 2; - uint64_t s_bist : 1; - uint64_t por : 1; - uint64_t enable : 1; - uint64_t prst : 1; - uint64_t hrst : 1; - uint64_t divide : 3; - } cn30xx; - struct cvmx_usbnx_clk_ctl_cn30xx cn31xx; - /** - * struct cvmx_usbnx_clk_ctl_cn50xx - * @divide2: The 'hclk' used by the USB subsystem is derived - * from the eclk. - * Also see the field DIVIDE. DIVIDE2<1> must currently - * be zero because it is not implemented, so the maximum - * ratio of eclk/hclk is currently 16. - * The actual divide number for hclk is: - * (DIVIDE2 + 1) * (DIVIDE + 1) - * @hclk_rst: When this field is '0' the HCLK-DIVIDER used to - * generate the hclk in the USB Subsystem is held - * in reset. This bit must be set to '0' before - * changing the value os DIVIDE in this register. - * The reset to the HCLK_DIVIDERis also asserted - * when core reset is asserted. - * @p_rtype: PHY reference clock type - * '0' The USB-PHY uses a 12MHz crystal as a clock - * source at the USB_XO and USB_XI pins - * '1' Reserved - * '2' The USB_PHY uses 12/24/48MHz 2.5V board clock - * at the USB_XO pin. USB_XI should be tied to - * ground in this case. - * '3' Reserved - * (bit 14 was P_XENBN on 3xxx) - * (bit 15 was P_RCLK on 3xxx) - * @p_com_on: '0' Force USB-PHY XO Bias, Bandgap and PLL to - * remain powered in Suspend Mode. - * '1' The USB-PHY XO Bias, Bandgap and PLL are - * powered down in suspend mode. - * The value of this field must be set while POR is - * active. - * @p_c_sel: Phy clock speed select. - * Selects the reference clock / crystal frequency. - * '11': Reserved - * '10': 48 MHz (reserved when a crystal is used) - * '01': 24 MHz (reserved when a crystal is used) - * '00': 12 MHz - * The value of this field must be set while POR is - * active. - * NOTE: if a crystal is used as a reference clock, - * this field must be set to 12 MHz. - * @cdiv_byp: Used to enable the bypass input to the USB_CLK_DIV. - * @sd_mode: Scaledown mode for the USBC. Control timing events - * in the USBC, for normal operation this must be '0'. - * @s_bist: Starts bist on the hclk memories, during the '0' - * to '1' transition. - * @por: Power On Reset for the PHY. - * Resets all the PHYS registers and state machines. - * @enable: When '1' allows the generation of the hclk. When - * '0' the hclk will not be generated. SEE DIVIDE - * field of this register. - * @prst: When this field is '0' the reset associated with - * the phy_clk functionality in the USB Subsystem is - * help in reset. This bit should not be set to '1' - * until the time it takes 6 clocks (hclk or phy_clk, - * whichever is slower) has passed. Under normal - * operation once this bit is set to '1' it should not - * be set to '0'. - * @hrst: When this field is '0' the reset associated with - * the hclk functioanlity in the USB Subsystem is - * held in reset.This bit should not be set to '1' - * until 12ms after phy_clk is stable. Under normal - * operation, once this bit is set to '1' it should - * not be set to '0'. - * @divide: The frequency of 'hclk' used by the USB subsystem - * is the eclk frequency divided by the value of - * (DIVIDE2 + 1) * (DIVIDE + 1), also see the field - * DIVIDE2 of this register. - * The hclk frequency should be less than 125Mhz. - * After writing a value to this field the SW should - * read the field for the value written. - * The ENABLE field of this register should not be set - * until AFTER this field is set and then read. - */ - struct cvmx_usbnx_clk_ctl_cn50xx { - uint64_t reserved_20_63 : 44; - uint64_t divide2 : 2; - uint64_t hclk_rst : 1; - uint64_t reserved_16_16 : 1; - uint64_t p_rtype : 2; - uint64_t p_com_on : 1; - uint64_t p_c_sel : 2; - uint64_t cdiv_byp : 1; - uint64_t sd_mode : 2; - uint64_t s_bist : 1; - uint64_t por : 1; - uint64_t enable : 1; - uint64_t prst : 1; - uint64_t hrst : 1; - uint64_t divide : 3; - } cn50xx; - struct cvmx_usbnx_clk_ctl_cn50xx cn52xx; - struct cvmx_usbnx_clk_ctl_cn50xx cn56xx; -}; - -/** - * cvmx_usbn#_usbp_ctl_status - * - * USBN_USBP_CTL_STATUS = USBP Control And Status Register - * - * Contains general control and status information for the USBN block. - */ -union cvmx_usbnx_usbp_ctl_status { - uint64_t u64; - /** - * struct cvmx_usbnx_usbp_ctl_status_s - * @txrisetune: HS Transmitter Rise/Fall Time Adjustment - * @txvreftune: HS DC Voltage Level Adjustment - * @txfslstune: FS/LS Source Impedence Adjustment - * @txhsxvtune: Transmitter High-Speed Crossover Adjustment - * @sqrxtune: Squelch Threshold Adjustment - * @compdistune: Disconnect Threshold Adjustment - * @otgtune: VBUS Valid Threshold Adjustment - * @otgdisable: OTG Block Disable - * @portreset: Per_Port Reset - * @drvvbus: Drive VBUS - * @lsbist: Low-Speed BIST Enable. - * @fsbist: Full-Speed BIST Enable. - * @hsbist: High-Speed BIST Enable. - * @bist_done: PHY Bist Done. - * Asserted at the end of the PHY BIST sequence. - * @bist_err: PHY Bist Error. - * Indicates an internal error was detected during - * the BIST sequence. - * @tdata_out: PHY Test Data Out. - * Presents either internaly generated signals or - * test register contents, based upon the value of - * test_data_out_sel. - * @siddq: Drives the USBP (USB-PHY) SIDDQ input. - * Normally should be set to zero. - * When customers have no intent to use USB PHY - * interface, they should: - * - still provide 3.3V to USB_VDD33, and - * - tie USB_REXT to 3.3V supply, and - * - set USBN*_USBP_CTL_STATUS[SIDDQ]=1 - * @txpreemphasistune: HS Transmitter Pre-Emphasis Enable - * @dma_bmode: When set to 1 the L2C DMA address will be updated - * with byte-counts between packets. When set to 0 - * the L2C DMA address is incremented to the next - * 4-byte aligned address after adding byte-count. - * @usbc_end: Bigendian input to the USB Core. This should be - * set to '0' for operation. - * @usbp_bist: PHY, This is cleared '0' to run BIST on the USBP. - * @tclk: PHY Test Clock, used to load TDATA_IN to the USBP. - * @dp_pulld: PHY DP_PULLDOWN input to the USB-PHY. - * This signal enables the pull-down resistance on - * the D+ line. '1' pull down-resistance is connected - * to D+/ '0' pull down resistance is not connected - * to D+. When an A/B device is acting as a host - * (downstream-facing port), dp_pulldown and - * dm_pulldown are enabled. This must not toggle - * during normal opeartion. - * @dm_pulld: PHY DM_PULLDOWN input to the USB-PHY. - * This signal enables the pull-down resistance on - * the D- line. '1' pull down-resistance is connected - * to D-. '0' pull down resistance is not connected - * to D-. When an A/B device is acting as a host - * (downstream-facing port), dp_pulldown and - * dm_pulldown are enabled. This must not toggle - * during normal opeartion. - * @hst_mode: When '0' the USB is acting as HOST, when '1' - * USB is acting as device. This field needs to be - * set while the USB is in reset. - * @tuning: Transmitter Tuning for High-Speed Operation. - * Tunes the current supply and rise/fall output - * times for high-speed operation. - * [20:19] == 11: Current supply increased - * approximately 9% - * [20:19] == 10: Current supply increased - * approximately 4.5% - * [20:19] == 01: Design default. - * [20:19] == 00: Current supply decreased - * approximately 4.5% - * [22:21] == 11: Rise and fall times are increased. - * [22:21] == 10: Design default. - * [22:21] == 01: Rise and fall times are decreased. - * [22:21] == 00: Rise and fall times are decreased - * further as compared to the 01 setting. - * @tx_bs_enh: Transmit Bit Stuffing on [15:8]. - * Enables or disables bit stuffing on data[15:8] - * when bit-stuffing is enabled. - * @tx_bs_en: Transmit Bit Stuffing on [7:0]. - * Enables or disables bit stuffing on data[7:0] - * when bit-stuffing is enabled. - * @loop_enb: PHY Loopback Test Enable. - * '1': During data transmission the receive is - * enabled. - * '0': During data transmission the receive is - * disabled. - * Must be '0' for normal operation. - * @vtest_enb: Analog Test Pin Enable. - * '1' The PHY's analog_test pin is enabled for the - * input and output of applicable analog test signals. - * '0' THe analog_test pin is disabled. - * @bist_enb: Built-In Self Test Enable. - * Used to activate BIST in the PHY. - * @tdata_sel: Test Data Out Select. - * '1' test_data_out[3:0] (PHY) register contents - * are output. '0' internaly generated signals are - * output. - * @taddr_in: Mode Address for Test Interface. - * Specifies the register address for writing to or - * reading from the PHY test interface register. - * @tdata_in: Internal Testing Register Input Data and Select - * This is a test bus. Data is present on [3:0], - * and its corresponding select (enable) is present - * on bits [7:4]. - * @ate_reset: Reset input from automatic test equipment. - * This is a test signal. When the USB Core is - * powered up (not in Susned Mode), an automatic - * tester can use this to disable phy_clock and - * free_clk, then re-eanable them with an aligned - * phase. - * '1': The phy_clk and free_clk outputs are - * disabled. "0": The phy_clock and free_clk outputs - * are available within a specific period after the - * de-assertion. - */ - struct cvmx_usbnx_usbp_ctl_status_s { - uint64_t txrisetune : 1; - uint64_t txvreftune : 4; - uint64_t txfslstune : 4; - uint64_t txhsxvtune : 2; - uint64_t sqrxtune : 3; - uint64_t compdistune : 3; - uint64_t otgtune : 3; - uint64_t otgdisable : 1; - uint64_t portreset : 1; - uint64_t drvvbus : 1; - uint64_t lsbist : 1; - uint64_t fsbist : 1; - uint64_t hsbist : 1; - uint64_t bist_done : 1; - uint64_t bist_err : 1; - uint64_t tdata_out : 4; - uint64_t siddq : 1; - uint64_t txpreemphasistune : 1; - uint64_t dma_bmode : 1; - uint64_t usbc_end : 1; - uint64_t usbp_bist : 1; - uint64_t tclk : 1; - uint64_t dp_pulld : 1; - uint64_t dm_pulld : 1; - uint64_t hst_mode : 1; - uint64_t tuning : 4; - uint64_t tx_bs_enh : 1; - uint64_t tx_bs_en : 1; - uint64_t loop_enb : 1; - uint64_t vtest_enb : 1; - uint64_t bist_enb : 1; - uint64_t tdata_sel : 1; - uint64_t taddr_in : 4; - uint64_t tdata_in : 8; - uint64_t ate_reset : 1; - } s; - /** - * struct cvmx_usbnx_usbp_ctl_status_cn30xx - * @bist_done: PHY Bist Done. - * Asserted at the end of the PHY BIST sequence. - * @bist_err: PHY Bist Error. - * Indicates an internal error was detected during - * the BIST sequence. - * @tdata_out: PHY Test Data Out. - * Presents either internaly generated signals or - * test register contents, based upon the value of - * test_data_out_sel. - * @dma_bmode: When set to 1 the L2C DMA address will be updated - * with byte-counts between packets. When set to 0 - * the L2C DMA address is incremented to the next - * 4-byte aligned address after adding byte-count. - * @usbc_end: Bigendian input to the USB Core. This should be - * set to '0' for operation. - * @usbp_bist: PHY, This is cleared '0' to run BIST on the USBP. - * @tclk: PHY Test Clock, used to load TDATA_IN to the USBP. - * @dp_pulld: PHY DP_PULLDOWN input to the USB-PHY. - * This signal enables the pull-down resistance on - * the D+ line. '1' pull down-resistance is connected - * to D+/ '0' pull down resistance is not connected - * to D+. When an A/B device is acting as a host - * (downstream-facing port), dp_pulldown and - * dm_pulldown are enabled. This must not toggle - * during normal opeartion. - * @dm_pulld: PHY DM_PULLDOWN input to the USB-PHY. - * This signal enables the pull-down resistance on - * the D- line. '1' pull down-resistance is connected - * to D-. '0' pull down resistance is not connected - * to D-. When an A/B device is acting as a host - * (downstream-facing port), dp_pulldown and - * dm_pulldown are enabled. This must not toggle - * during normal opeartion. - * @hst_mode: When '0' the USB is acting as HOST, when '1' - * USB is acting as device. This field needs to be - * set while the USB is in reset. - * @tuning: Transmitter Tuning for High-Speed Operation. - * Tunes the current supply and rise/fall output - * times for high-speed operation. - * [20:19] == 11: Current supply increased - * approximately 9% - * [20:19] == 10: Current supply increased - * approximately 4.5% - * [20:19] == 01: Design default. - * [20:19] == 00: Current supply decreased - * approximately 4.5% - * [22:21] == 11: Rise and fall times are increased. - * [22:21] == 10: Design default. - * [22:21] == 01: Rise and fall times are decreased. - * [22:21] == 00: Rise and fall times are decreased - * further as compared to the 01 setting. - * @tx_bs_enh: Transmit Bit Stuffing on [15:8]. - * Enables or disables bit stuffing on data[15:8] - * when bit-stuffing is enabled. - * @tx_bs_en: Transmit Bit Stuffing on [7:0]. - * Enables or disables bit stuffing on data[7:0] - * when bit-stuffing is enabled. - * @loop_enb: PHY Loopback Test Enable. - * '1': During data transmission the receive is - * enabled. - * '0': During data transmission the receive is - * disabled. - * Must be '0' for normal operation. - * @vtest_enb: Analog Test Pin Enable. - * '1' The PHY's analog_test pin is enabled for the - * input and output of applicable analog test signals. - * '0' THe analog_test pin is disabled. - * @bist_enb: Built-In Self Test Enable. - * Used to activate BIST in the PHY. - * @tdata_sel: Test Data Out Select. - * '1' test_data_out[3:0] (PHY) register contents - * are output. '0' internaly generated signals are - * output. - * @taddr_in: Mode Address for Test Interface. - * Specifies the register address for writing to or - * reading from the PHY test interface register. - * @tdata_in: Internal Testing Register Input Data and Select - * This is a test bus. Data is present on [3:0], - * and its corresponding select (enable) is present - * on bits [7:4]. - * @ate_reset: Reset input from automatic test equipment. - * This is a test signal. When the USB Core is - * powered up (not in Susned Mode), an automatic - * tester can use this to disable phy_clock and - * free_clk, then re-eanable them with an aligned - * phase. - * '1': The phy_clk and free_clk outputs are - * disabled. "0": The phy_clock and free_clk outputs - * are available within a specific period after the - * de-assertion. - */ - struct cvmx_usbnx_usbp_ctl_status_cn30xx { - uint64_t reserved_38_63 : 26; - uint64_t bist_done : 1; - uint64_t bist_err : 1; - uint64_t tdata_out : 4; - uint64_t reserved_30_31 : 2; - uint64_t dma_bmode : 1; - uint64_t usbc_end : 1; - uint64_t usbp_bist : 1; - uint64_t tclk : 1; - uint64_t dp_pulld : 1; - uint64_t dm_pulld : 1; - uint64_t hst_mode : 1; - uint64_t tuning : 4; - uint64_t tx_bs_enh : 1; - uint64_t tx_bs_en : 1; - uint64_t loop_enb : 1; - uint64_t vtest_enb : 1; - uint64_t bist_enb : 1; - uint64_t tdata_sel : 1; - uint64_t taddr_in : 4; - uint64_t tdata_in : 8; - uint64_t ate_reset : 1; - } cn30xx; - /** - * struct cvmx_usbnx_usbp_ctl_status_cn50xx - * @txrisetune: HS Transmitter Rise/Fall Time Adjustment - * @txvreftune: HS DC Voltage Level Adjustment - * @txfslstune: FS/LS Source Impedence Adjustment - * @txhsxvtune: Transmitter High-Speed Crossover Adjustment - * @sqrxtune: Squelch Threshold Adjustment - * @compdistune: Disconnect Threshold Adjustment - * @otgtune: VBUS Valid Threshold Adjustment - * @otgdisable: OTG Block Disable - * @portreset: Per_Port Reset - * @drvvbus: Drive VBUS - * @lsbist: Low-Speed BIST Enable. - * @fsbist: Full-Speed BIST Enable. - * @hsbist: High-Speed BIST Enable. - * @bist_done: PHY Bist Done. - * Asserted at the end of the PHY BIST sequence. - * @bist_err: PHY Bist Error. - * Indicates an internal error was detected during - * the BIST sequence. - * @tdata_out: PHY Test Data Out. - * Presents either internaly generated signals or - * test register contents, based upon the value of - * test_data_out_sel. - * @txpreemphasistune: HS Transmitter Pre-Emphasis Enable - * @dma_bmode: When set to 1 the L2C DMA address will be updated - * with byte-counts between packets. When set to 0 - * the L2C DMA address is incremented to the next - * 4-byte aligned address after adding byte-count. - * @usbc_end: Bigendian input to the USB Core. This should be - * set to '0' for operation. - * @usbp_bist: PHY, This is cleared '0' to run BIST on the USBP. - * @tclk: PHY Test Clock, used to load TDATA_IN to the USBP. - * @dp_pulld: PHY DP_PULLDOWN input to the USB-PHY. - * This signal enables the pull-down resistance on - * the D+ line. '1' pull down-resistance is connected - * to D+/ '0' pull down resistance is not connected - * to D+. When an A/B device is acting as a host - * (downstream-facing port), dp_pulldown and - * dm_pulldown are enabled. This must not toggle - * during normal opeartion. - * @dm_pulld: PHY DM_PULLDOWN input to the USB-PHY. - * This signal enables the pull-down resistance on - * the D- line. '1' pull down-resistance is connected - * to D-. '0' pull down resistance is not connected - * to D-. When an A/B device is acting as a host - * (downstream-facing port), dp_pulldown and - * dm_pulldown are enabled. This must not toggle - * during normal opeartion. - * @hst_mode: When '0' the USB is acting as HOST, when '1' - * USB is acting as device. This field needs to be - * set while the USB is in reset. - * @tx_bs_enh: Transmit Bit Stuffing on [15:8]. - * Enables or disables bit stuffing on data[15:8] - * when bit-stuffing is enabled. - * @tx_bs_en: Transmit Bit Stuffing on [7:0]. - * Enables or disables bit stuffing on data[7:0] - * when bit-stuffing is enabled. - * @loop_enb: PHY Loopback Test Enable. - * '1': During data transmission the receive is - * enabled. - * '0': During data transmission the receive is - * disabled. - * Must be '0' for normal operation. - * @vtest_enb: Analog Test Pin Enable. - * '1' The PHY's analog_test pin is enabled for the - * input and output of applicable analog test signals. - * '0' THe analog_test pin is disabled. - * @bist_enb: Built-In Self Test Enable. - * Used to activate BIST in the PHY. - * @tdata_sel: Test Data Out Select. - * '1' test_data_out[3:0] (PHY) register contents - * are output. '0' internaly generated signals are - * output. - * @taddr_in: Mode Address for Test Interface. - * Specifies the register address for writing to or - * reading from the PHY test interface register. - * @tdata_in: Internal Testing Register Input Data and Select - * This is a test bus. Data is present on [3:0], - * and its corresponding select (enable) is present - * on bits [7:4]. - * @ate_reset: Reset input from automatic test equipment. - * This is a test signal. When the USB Core is - * powered up (not in Susned Mode), an automatic - * tester can use this to disable phy_clock and - * free_clk, then re-eanable them with an aligned - * phase. - * '1': The phy_clk and free_clk outputs are - * disabled. "0": The phy_clock and free_clk outputs - * are available within a specific period after the - * de-assertion. - */ - struct cvmx_usbnx_usbp_ctl_status_cn50xx { - uint64_t txrisetune : 1; - uint64_t txvreftune : 4; - uint64_t txfslstune : 4; - uint64_t txhsxvtune : 2; - uint64_t sqrxtune : 3; - uint64_t compdistune : 3; - uint64_t otgtune : 3; - uint64_t otgdisable : 1; - uint64_t portreset : 1; - uint64_t drvvbus : 1; - uint64_t lsbist : 1; - uint64_t fsbist : 1; - uint64_t hsbist : 1; - uint64_t bist_done : 1; - uint64_t bist_err : 1; - uint64_t tdata_out : 4; - uint64_t reserved_31_31 : 1; - uint64_t txpreemphasistune : 1; - uint64_t dma_bmode : 1; - uint64_t usbc_end : 1; - uint64_t usbp_bist : 1; - uint64_t tclk : 1; - uint64_t dp_pulld : 1; - uint64_t dm_pulld : 1; - uint64_t hst_mode : 1; - uint64_t reserved_19_22 : 4; - uint64_t tx_bs_enh : 1; - uint64_t tx_bs_en : 1; - uint64_t loop_enb : 1; - uint64_t vtest_enb : 1; - uint64_t bist_enb : 1; - uint64_t tdata_sel : 1; - uint64_t taddr_in : 4; - uint64_t tdata_in : 8; - uint64_t ate_reset : 1; - } cn50xx; - /** - * struct cvmx_usbnx_usbp_ctl_status_cn52xx - * @txrisetune: HS Transmitter Rise/Fall Time Adjustment - * @txvreftune: HS DC Voltage Level Adjustment - * @txfslstune: FS/LS Source Impedence Adjustment - * @txhsxvtune: Transmitter High-Speed Crossover Adjustment - * @sqrxtune: Squelch Threshold Adjustment - * @compdistune: Disconnect Threshold Adjustment - * @otgtune: VBUS Valid Threshold Adjustment - * @otgdisable: OTG Block Disable - * @portreset: Per_Port Reset - * @drvvbus: Drive VBUS - * @lsbist: Low-Speed BIST Enable. - * @fsbist: Full-Speed BIST Enable. - * @hsbist: High-Speed BIST Enable. - * @bist_done: PHY Bist Done. - * Asserted at the end of the PHY BIST sequence. - * @bist_err: PHY Bist Error. - * Indicates an internal error was detected during - * the BIST sequence. - * @tdata_out: PHY Test Data Out. - * Presents either internaly generated signals or - * test register contents, based upon the value of - * test_data_out_sel. - * @siddq: Drives the USBP (USB-PHY) SIDDQ input. - * Normally should be set to zero. - * When customers have no intent to use USB PHY - * interface, they should: - * - still provide 3.3V to USB_VDD33, and - * - tie USB_REXT to 3.3V supply, and - * - set USBN*_USBP_CTL_STATUS[SIDDQ]=1 - * @txpreemphasistune: HS Transmitter Pre-Emphasis Enable - * @dma_bmode: When set to 1 the L2C DMA address will be updated - * with byte-counts between packets. When set to 0 - * the L2C DMA address is incremented to the next - * 4-byte aligned address after adding byte-count. - * @usbc_end: Bigendian input to the USB Core. This should be - * set to '0' for operation. - * @usbp_bist: PHY, This is cleared '0' to run BIST on the USBP. - * @tclk: PHY Test Clock, used to load TDATA_IN to the USBP. - * @dp_pulld: PHY DP_PULLDOWN input to the USB-PHY. - * This signal enables the pull-down resistance on - * the D+ line. '1' pull down-resistance is connected - * to D+/ '0' pull down resistance is not connected - * to D+. When an A/B device is acting as a host - * (downstream-facing port), dp_pulldown and - * dm_pulldown are enabled. This must not toggle - * during normal opeartion. - * @dm_pulld: PHY DM_PULLDOWN input to the USB-PHY. - * This signal enables the pull-down resistance on - * the D- line. '1' pull down-resistance is connected - * to D-. '0' pull down resistance is not connected - * to D-. When an A/B device is acting as a host - * (downstream-facing port), dp_pulldown and - * dm_pulldown are enabled. This must not toggle - * during normal opeartion. - * @hst_mode: When '0' the USB is acting as HOST, when '1' - * USB is acting as device. This field needs to be - * set while the USB is in reset. - * @tx_bs_enh: Transmit Bit Stuffing on [15:8]. - * Enables or disables bit stuffing on data[15:8] - * when bit-stuffing is enabled. - * @tx_bs_en: Transmit Bit Stuffing on [7:0]. - * Enables or disables bit stuffing on data[7:0] - * when bit-stuffing is enabled. - * @loop_enb: PHY Loopback Test Enable. - * '1': During data transmission the receive is - * enabled. - * '0': During data transmission the receive is - * disabled. - * Must be '0' for normal operation. - * @vtest_enb: Analog Test Pin Enable. - * '1' The PHY's analog_test pin is enabled for the - * input and output of applicable analog test signals. - * '0' THe analog_test pin is disabled. - * @bist_enb: Built-In Self Test Enable. - * Used to activate BIST in the PHY. - * @tdata_sel: Test Data Out Select. - * '1' test_data_out[3:0] (PHY) register contents - * are output. '0' internaly generated signals are - * output. - * @taddr_in: Mode Address for Test Interface. - * Specifies the register address for writing to or - * reading from the PHY test interface register. - * @tdata_in: Internal Testing Register Input Data and Select - * This is a test bus. Data is present on [3:0], - * and its corresponding select (enable) is present - * on bits [7:4]. - * @ate_reset: Reset input from automatic test equipment. - * This is a test signal. When the USB Core is - * powered up (not in Susned Mode), an automatic - * tester can use this to disable phy_clock and - * free_clk, then re-eanable them with an aligned - * phase. - * '1': The phy_clk and free_clk outputs are - * disabled. "0": The phy_clock and free_clk outputs - * are available within a specific period after the - * de-assertion. - */ - struct cvmx_usbnx_usbp_ctl_status_cn52xx { - uint64_t txrisetune : 1; - uint64_t txvreftune : 4; - uint64_t txfslstune : 4; - uint64_t txhsxvtune : 2; - uint64_t sqrxtune : 3; - uint64_t compdistune : 3; - uint64_t otgtune : 3; - uint64_t otgdisable : 1; - uint64_t portreset : 1; - uint64_t drvvbus : 1; - uint64_t lsbist : 1; - uint64_t fsbist : 1; - uint64_t hsbist : 1; - uint64_t bist_done : 1; - uint64_t bist_err : 1; - uint64_t tdata_out : 4; - uint64_t siddq : 1; - uint64_t txpreemphasistune : 1; - uint64_t dma_bmode : 1; - uint64_t usbc_end : 1; - uint64_t usbp_bist : 1; - uint64_t tclk : 1; - uint64_t dp_pulld : 1; - uint64_t dm_pulld : 1; - uint64_t hst_mode : 1; - uint64_t reserved_19_22 : 4; - uint64_t tx_bs_enh : 1; - uint64_t tx_bs_en : 1; - uint64_t loop_enb : 1; - uint64_t vtest_enb : 1; - uint64_t bist_enb : 1; - uint64_t tdata_sel : 1; - uint64_t taddr_in : 4; - uint64_t tdata_in : 8; - uint64_t ate_reset : 1; - } cn52xx; -}; - -#endif diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c index 5dbbd14ec615..d118952c0a74 100644 --- a/drivers/staging/octeon-usb/octeon-hcd.c +++ b/drivers/staging/octeon-usb/octeon-hcd.c @@ -4,6 +4,44 @@ * for more details. * * Copyright (C) 2008 Cavium Networks + * + * Some parts of the code were originally released under BSD license: + * + * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Cavium Networks nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * This Software, including technical data, may be subject to U.S. export + * control laws, including the U.S. Export Administration Act and its associated + * regulations, and may be subject to export or import regulations in other + * countries. + * + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" + * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR + * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO + * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION + * OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM + * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, + * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF + * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR + * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR + * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. */ #include <linux/kernel.h> #include <linux/module.h> @@ -17,13 +55,379 @@ #include <linux/delay.h> #include <asm/octeon/cvmx.h> -#include "cvmx-usb.h" #include <asm/octeon/cvmx-iob-defs.h> #include <linux/usb/hcd.h> #include <linux/err.h> +#include <asm/octeon/octeon.h> +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-sysinfo.h> +#include <asm/octeon/cvmx-helper-board.h> + +#include "octeon-hcd.h" + +/** + * enum cvmx_usb_speed - the possible USB device speeds + * + * @CVMX_USB_SPEED_HIGH: Device is operation at 480Mbps + * @CVMX_USB_SPEED_FULL: Device is operation at 12Mbps + * @CVMX_USB_SPEED_LOW: Device is operation at 1.5Mbps + */ +enum cvmx_usb_speed { + CVMX_USB_SPEED_HIGH = 0, + CVMX_USB_SPEED_FULL = 1, + CVMX_USB_SPEED_LOW = 2, +}; + +/** + * enum cvmx_usb_transfer - the possible USB transfer types + * + * @CVMX_USB_TRANSFER_CONTROL: USB transfer type control for hub and status + * transfers + * @CVMX_USB_TRANSFER_ISOCHRONOUS: USB transfer type isochronous for low + * priority periodic transfers + * @CVMX_USB_TRANSFER_BULK: USB transfer type bulk for large low priority + * transfers + * @CVMX_USB_TRANSFER_INTERRUPT: USB transfer type interrupt for high priority + * periodic transfers + */ +enum cvmx_usb_transfer { + CVMX_USB_TRANSFER_CONTROL = 0, + CVMX_USB_TRANSFER_ISOCHRONOUS = 1, + CVMX_USB_TRANSFER_BULK = 2, + CVMX_USB_TRANSFER_INTERRUPT = 3, +}; + +/** + * enum cvmx_usb_direction - the transfer directions + * + * @CVMX_USB_DIRECTION_OUT: Data is transferring from Octeon to the device/host + * @CVMX_USB_DIRECTION_IN: Data is transferring from the device/host to Octeon + */ +enum cvmx_usb_direction { + CVMX_USB_DIRECTION_OUT, + CVMX_USB_DIRECTION_IN, +}; + +/** + * enum cvmx_usb_complete - possible callback function status codes + * + * @CVMX_USB_COMPLETE_SUCCESS: The transaction / operation finished without + * any errors + * @CVMX_USB_COMPLETE_SHORT: FIXME: This is currently not implemented + * @CVMX_USB_COMPLETE_CANCEL: The transaction was canceled while in flight + * by a user call to cvmx_usb_cancel + * @CVMX_USB_COMPLETE_ERROR: The transaction aborted with an unexpected + * error status + * @CVMX_USB_COMPLETE_STALL: The transaction received a USB STALL response + * from the device + * @CVMX_USB_COMPLETE_XACTERR: The transaction failed with an error from the + * device even after a number of retries + * @CVMX_USB_COMPLETE_DATATGLERR: The transaction failed with a data toggle + * error even after a number of retries + * @CVMX_USB_COMPLETE_BABBLEERR: The transaction failed with a babble error + * @CVMX_USB_COMPLETE_FRAMEERR: The transaction failed with a frame error + * even after a number of retries + */ +enum cvmx_usb_complete { + CVMX_USB_COMPLETE_SUCCESS, + CVMX_USB_COMPLETE_SHORT, + CVMX_USB_COMPLETE_CANCEL, + CVMX_USB_COMPLETE_ERROR, + CVMX_USB_COMPLETE_STALL, + CVMX_USB_COMPLETE_XACTERR, + CVMX_USB_COMPLETE_DATATGLERR, + CVMX_USB_COMPLETE_BABBLEERR, + CVMX_USB_COMPLETE_FRAMEERR, +}; + +/** + * struct cvmx_usb_port_status - the USB port status information + * + * @port_enabled: 1 = Usb port is enabled, 0 = disabled + * @port_over_current: 1 = Over current detected, 0 = Over current not + * detected. Octeon doesn't support over current detection. + * @port_powered: 1 = Port power is being supplied to the device, 0 = + * power is off. Octeon doesn't support turning port power + * off. + * @port_speed: Current port speed. + * @connected: 1 = A device is connected to the port, 0 = No device is + * connected. + * @connect_change: 1 = Device connected state changed since the last set + * status call. + */ +struct cvmx_usb_port_status { + uint32_t reserved : 25; + uint32_t port_enabled : 1; + uint32_t port_over_current : 1; + uint32_t port_powered : 1; + enum cvmx_usb_speed port_speed : 2; + uint32_t connected : 1; + uint32_t connect_change : 1; +}; + +/** + * union cvmx_usb_control_header - the structure of a Control packet header + * + * @s.request_type: Bit 7 tells the direction: 1=IN, 0=OUT + * @s.request The standard usb request to make + * @s.value Value parameter for the request in little endian format + * @s.index Index for the request in little endian format + * @s.length Length of the data associated with this request in + * little endian format + */ +union cvmx_usb_control_header { + uint64_t u64; + struct { + uint64_t request_type : 8; + uint64_t request : 8; + uint64_t value : 16; + uint64_t index : 16; + uint64_t length : 16; + } s; +}; + +/** + * struct cvmx_usb_iso_packet - descriptor for Isochronous packets + * + * @offset: This is the offset in bytes into the main buffer where this data + * is stored. + * @length: This is the length in bytes of the data. + * @status: This is the status of this individual packet transfer. + */ +struct cvmx_usb_iso_packet { + int offset; + int length; + enum cvmx_usb_complete status; +}; + +/** + * enum cvmx_usb_initialize_flags - flags used by the initialization function + * + * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI: The USB port uses a 12MHz crystal + * as clock source at USB_XO and + * USB_XI. + * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND: The USB port uses 12/24/48MHz 2.5V + * board clock source at USB_XO. + * USB_XI should be tied to GND. + * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK: Mask for clock speed field + * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ: Speed of reference clock or + * crystal + * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ: Speed of reference clock + * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ: Speed of reference clock + * @CVMX_USB_INITIALIZE_FLAGS_NO_DMA: Disable DMA and used polled IO for + * data transfer use for the USB + */ +enum cvmx_usb_initialize_flags { + CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI = 1 << 0, + CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND = 1 << 1, + CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK = 3 << 3, + CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ = 1 << 3, + CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ = 2 << 3, + CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ = 3 << 3, + /* Bits 3-4 used to encode the clock frequency */ + CVMX_USB_INITIALIZE_FLAGS_NO_DMA = 1 << 5, +}; + +/** + * enum cvmx_usb_pipe_flags - internal flags for a pipe. + * + * @__CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is + * actively using hardware. Do not use. + * @__CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high + * speed pipe is in the ping state. Do not + * use. + */ +enum cvmx_usb_pipe_flags { + __CVMX_USB_PIPE_FLAGS_SCHEDULED = 1 << 17, + __CVMX_USB_PIPE_FLAGS_NEED_PING = 1 << 18, +}; + +/* Normal prefetch that use the pref instruction. */ +#define CVMX_PREFETCH(address, offset) asm volatile ("pref %[type], %[off](%[rbase])" : : [rbase] "d" (address), [off] "I" (offset), [type] "n" (0)) + +/* Maximum number of times to retry failed transactions */ +#define MAX_RETRIES 3 + +/* Maximum number of hardware channels supported by the USB block */ +#define MAX_CHANNELS 8 + +/* The highest valid USB device address */ +#define MAX_USB_ADDRESS 127 + +/* The highest valid USB endpoint number */ +#define MAX_USB_ENDPOINT 15 + +/* The highest valid port number on a hub */ +#define MAX_USB_HUB_PORT 15 + +/* + * The low level hardware can transfer a maximum of this number of bytes in each + * transfer. The field is 19 bits wide + */ +#define MAX_TRANSFER_BYTES ((1<<19)-1) + +/* + * The low level hardware can transfer a maximum of this number of packets in + * each transfer. The field is 10 bits wide + */ +#define MAX_TRANSFER_PACKETS ((1<<10)-1) + +enum { + USB_CLOCK_TYPE_REF_12, + USB_CLOCK_TYPE_REF_24, + USB_CLOCK_TYPE_REF_48, + USB_CLOCK_TYPE_CRYSTAL_12, +}; + +/** + * Logical transactions may take numerous low level + * transactions, especially when splits are concerned. This + * enum represents all of the possible stages a transaction can + * be in. Note that split completes are always even. This is so + * the NAK handler can backup to the previous low level + * transaction with a simple clearing of bit 0. + */ +enum cvmx_usb_stage { + CVMX_USB_STAGE_NON_CONTROL, + CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE, + CVMX_USB_STAGE_SETUP, + CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE, + CVMX_USB_STAGE_DATA, + CVMX_USB_STAGE_DATA_SPLIT_COMPLETE, + CVMX_USB_STAGE_STATUS, + CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE, +}; + +/** + * struct cvmx_usb_transaction - describes each pending USB transaction + * regardless of type. These are linked together + * to form a list of pending requests for a pipe. + * + * @node: List node for transactions in the pipe. + * @type: Type of transaction, duplicated of the pipe. + * @flags: State flags for this transaction. + * @buffer: User's physical buffer address to read/write. + * @buffer_length: Size of the user's buffer in bytes. + * @control_header: For control transactions, physical address of the 8 + * byte standard header. + * @iso_start_frame: For ISO transactions, the starting frame number. + * @iso_number_packets: For ISO transactions, the number of packets in the + * request. + * @iso_packets: For ISO transactions, the sub packets in the request. + * @actual_bytes: Actual bytes transfer for this transaction. + * @stage: For control transactions, the current stage. + * @urb: URB. + */ +struct cvmx_usb_transaction { + struct list_head node; + enum cvmx_usb_transfer type; + uint64_t buffer; + int buffer_length; + uint64_t control_header; + int iso_start_frame; + int iso_number_packets; + struct cvmx_usb_iso_packet *iso_packets; + int xfersize; + int pktcnt; + int retries; + int actual_bytes; + enum cvmx_usb_stage stage; + struct urb *urb; +}; + +/** + * struct cvmx_usb_pipe - a pipe represents a virtual connection between Octeon + * and some USB device. It contains a list of pending + * request to the device. + * + * @node: List node for pipe list + * @next: Pipe after this one in the list + * @transactions: List of pending transactions + * @interval: For periodic pipes, the interval between packets in + * frames + * @next_tx_frame: The next frame this pipe is allowed to transmit on + * @flags: State flags for this pipe + * @device_speed: Speed of device connected to this pipe + * @transfer_type: Type of transaction supported by this pipe + * @transfer_dir: IN or OUT. Ignored for Control + * @multi_count: Max packet in a row for the device + * @max_packet: The device's maximum packet size in bytes + * @device_addr: USB device address at other end of pipe + * @endpoint_num: USB endpoint number at other end of pipe + * @hub_device_addr: Hub address this device is connected to + * @hub_port: Hub port this device is connected to + * @pid_toggle: This toggles between 0/1 on every packet send to track + * the data pid needed + * @channel: Hardware DMA channel for this pipe + * @split_sc_frame: The low order bits of the frame number the split + * complete should be sent on + */ +struct cvmx_usb_pipe { + struct list_head node; + struct list_head transactions; + uint64_t interval; + uint64_t next_tx_frame; + enum cvmx_usb_pipe_flags flags; + enum cvmx_usb_speed device_speed; + enum cvmx_usb_transfer transfer_type; + enum cvmx_usb_direction transfer_dir; + int multi_count; + uint16_t max_packet; + uint8_t device_addr; + uint8_t endpoint_num; + uint8_t hub_device_addr; + uint8_t hub_port; + uint8_t pid_toggle; + uint8_t channel; + int8_t split_sc_frame; +}; + +struct cvmx_usb_tx_fifo { + struct { + int channel; + int size; + uint64_t address; + } entry[MAX_CHANNELS+1]; + int head; + int tail; +}; + +/** + * struct cvmx_usb_state - the state of the USB block + * + * init_flags: Flags passed to initialize. + * index: Which USB block this is for. + * idle_hardware_channels: Bit set for every idle hardware channel. + * usbcx_hprt: Stored port status so we don't need to read a CSR to + * determine splits. + * pipe_for_channel: Map channels to pipes. + * pipe: Storage for pipes. + * indent: Used by debug output to indent functions. + * port_status: Last port status used for change notification. + * idle_pipes: List of open pipes that have no transactions. + * active_pipes: Active pipes indexed by transfer type. + * frame_number: Increments every SOF interrupt for time keeping. + * active_split: Points to the current active split, or NULL. + */ +struct cvmx_usb_state { + int init_flags; + int index; + int idle_hardware_channels; + union cvmx_usbcx_hprt usbcx_hprt; + struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS]; + int indent; + struct cvmx_usb_port_status port_status; + struct list_head idle_pipes; + struct list_head active_pipes[4]; + uint64_t frame_number; + struct cvmx_usb_transaction *active_split; + struct cvmx_usb_tx_fifo periodic; + struct cvmx_usb_tx_fifo nonperiodic; +}; + struct octeon_hcd { spinlock_t lock; struct cvmx_usb_state usb; @@ -31,107 +435,1565 @@ struct octeon_hcd { struct list_head dequeue_list; }; -/* convert between an HCD pointer and the corresponding struct octeon_hcd */ -static inline struct octeon_hcd *hcd_to_octeon(struct usb_hcd *hcd) +/* This macro spins on a field waiting for it to reach a value */ +#define CVMX_WAIT_FOR_FIELD32(address, type, field, op, value, timeout_usec)\ + ({int result; \ + do { \ + uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \ + octeon_get_clock_rate() / 1000000; \ + type c; \ + while (1) { \ + c.u32 = __cvmx_usb_read_csr32(usb, address); \ + if (c.s.field op (value)) { \ + result = 0; \ + break; \ + } else if (cvmx_get_cycle() > done) { \ + result = -1; \ + break; \ + } else \ + cvmx_wait(100); \ + } \ + } while (0); \ + result; }) + +/* + * This macro logically sets a single field in a CSR. It does the sequence + * read, modify, and write + */ +#define USB_SET_FIELD32(address, type, field, value) \ + do { \ + type c; \ + c.u32 = __cvmx_usb_read_csr32(usb, address); \ + c.s.field = value; \ + __cvmx_usb_write_csr32(usb, address, c.u32); \ + } while (0) + +/* Returns the IO address to push/pop stuff data from the FIFOs */ +#define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000) + +static int octeon_usb_get_clock_type(void) { - return (struct octeon_hcd *)(hcd->hcd_priv); + switch (cvmx_sysinfo_get()->board_type) { + case CVMX_BOARD_TYPE_BBGW_REF: + case CVMX_BOARD_TYPE_LANAI2_A: + case CVMX_BOARD_TYPE_LANAI2_U: + case CVMX_BOARD_TYPE_LANAI2_G: + case CVMX_BOARD_TYPE_UBNT_E100: + return USB_CLOCK_TYPE_CRYSTAL_12; + } + return USB_CLOCK_TYPE_REF_48; } -static inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p) +/** + * Read a USB 32bit CSR. It performs the necessary address swizzle + * for 32bit CSRs and logs the value in a readable format if + * debugging is on. + * + * @usb: USB block this access is for + * @address: 64bit address to read + * + * Returns: Result of the read + */ +static inline uint32_t __cvmx_usb_read_csr32(struct cvmx_usb_state *usb, + uint64_t address) { - return container_of((void *)p, struct usb_hcd, hcd_priv); + uint32_t result = cvmx_read64_uint32(address ^ 4); + return result; } -static inline struct octeon_hcd *cvmx_usb_to_octeon(struct cvmx_usb_state *p) + +/** + * Write a USB 32bit CSR. It performs the necessary address + * swizzle for 32bit CSRs and logs the value in a readable format + * if debugging is on. + * + * @usb: USB block this access is for + * @address: 64bit address to write + * @value: Value to write + */ +static inline void __cvmx_usb_write_csr32(struct cvmx_usb_state *usb, + uint64_t address, uint32_t value) { - return container_of(p, struct octeon_hcd, usb); + cvmx_write64_uint32(address ^ 4, value); + cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); } -static irqreturn_t octeon_usb_irq(struct usb_hcd *hcd) + +/** + * Read a USB 64bit CSR. It logs the value in a readable format if + * debugging is on. + * + * @usb: USB block this access is for + * @address: 64bit address to read + * + * Returns: Result of the read + */ +static inline uint64_t __cvmx_usb_read_csr64(struct cvmx_usb_state *usb, + uint64_t address) { - struct octeon_hcd *priv = hcd_to_octeon(hcd); - unsigned long flags; + uint64_t result = cvmx_read64_uint64(address); + return result; +} - spin_lock_irqsave(&priv->lock, flags); - cvmx_usb_poll(&priv->usb); - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_HANDLED; + +/** + * Write a USB 64bit CSR. It logs the value in a readable format + * if debugging is on. + * + * @usb: USB block this access is for + * @address: 64bit address to write + * @value: Value to write + */ +static inline void __cvmx_usb_write_csr64(struct cvmx_usb_state *usb, + uint64_t address, uint64_t value) +{ + cvmx_write64_uint64(address, value); } -static void octeon_usb_port_callback(struct cvmx_usb_state *usb, - enum cvmx_usb_callback reason, - enum cvmx_usb_complete status, - int pipe_handle, - int submit_handle, - int bytes_transferred, - void *user_data) +/** + * Return non zero if this pipe connects to a non HIGH speed + * device through a high speed hub. + * + * @usb: USB block this access is for + * @pipe: Pipe to check + * + * Returns: Non zero if we need to do split transactions + */ +static inline int __cvmx_usb_pipe_needs_split(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe) { - struct octeon_hcd *priv = cvmx_usb_to_octeon(usb); + return pipe->device_speed != CVMX_USB_SPEED_HIGH && + usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH; +} - spin_unlock(&priv->lock); - usb_hcd_poll_rh_status(octeon_to_hcd(priv)); - spin_lock(&priv->lock); + +/** + * Trivial utility function to return the correct PID for a pipe + * + * @pipe: pipe to check + * + * Returns: PID for pipe + */ +static inline int __cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe) +{ + if (pipe->pid_toggle) + return 2; /* Data1 */ + else + return 0; /* Data0 */ } -static int octeon_usb_start(struct usb_hcd *hcd) + +/** + * Return the number of USB ports supported by this Octeon + * chip. If the chip doesn't support USB, or is not supported + * by this API, a zero will be returned. Most Octeon chips + * support one usb port, but some support two ports. + * cvmx_usb_initialize() must be called on independent + * struct cvmx_usb_state. + * + * Returns: Number of port, zero if usb isn't supported + */ +static int cvmx_usb_get_num_ports(void) { - struct octeon_hcd *priv = hcd_to_octeon(hcd); - unsigned long flags; + int arch_ports = 0; + + if (OCTEON_IS_MODEL(OCTEON_CN56XX)) + arch_ports = 1; + else if (OCTEON_IS_MODEL(OCTEON_CN52XX)) + arch_ports = 2; + else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) + arch_ports = 1; + else if (OCTEON_IS_MODEL(OCTEON_CN31XX)) + arch_ports = 1; + else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) + arch_ports = 1; + else + arch_ports = 0; + + return arch_ports; +} + +/** + * Initialize a USB port for use. This must be called before any + * other access to the Octeon USB port is made. The port starts + * off in the disabled state. + * + * @usb: Pointer to an empty struct cvmx_usb_state + * that will be populated by the initialize call. + * This structure is then passed to all other USB + * functions. + * @usb_port_number: + * Which Octeon USB port to initialize. + * + * Returns: 0 or a negative error code. + */ +static int cvmx_usb_initialize(struct cvmx_usb_state *usb, + int usb_port_number) +{ + union cvmx_usbnx_clk_ctl usbn_clk_ctl; + union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status; + enum cvmx_usb_initialize_flags flags = 0; + int i; + + /* At first allow 0-1 for the usb port number */ + if ((usb_port_number < 0) || (usb_port_number > 1)) + return -EINVAL; + /* For all chips except 52XX there is only one port */ + if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0)) + return -EINVAL; + /* Try to determine clock type automatically */ + if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12) { + /* Only 12 MHZ crystals are supported */ + flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI; + } else { + flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND; + + switch (octeon_usb_get_clock_type()) { + case USB_CLOCK_TYPE_REF_12: + flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ; + break; + case USB_CLOCK_TYPE_REF_24: + flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ; + break; + case USB_CLOCK_TYPE_REF_48: + flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ; + break; + default: + return -EINVAL; + break; + } + } + + memset(usb, 0, sizeof(*usb)); + usb->init_flags = flags; + + /* Initialize the USB state structure */ + usb->index = usb_port_number; + INIT_LIST_HEAD(&usb->idle_pipes); + for (i = 0; i < ARRAY_SIZE(usb->active_pipes); i++) + INIT_LIST_HEAD(&usb->active_pipes[i]); + + /* + * Power On Reset and PHY Initialization + * + * 1. Wait for DCOK to assert (nothing to do) + * + * 2a. Write USBN0/1_CLK_CTL[POR] = 1 and + * USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0 + */ + usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index)); + usbn_clk_ctl.s.por = 1; + usbn_clk_ctl.s.hrst = 0; + usbn_clk_ctl.s.prst = 0; + usbn_clk_ctl.s.hclk_rst = 0; + usbn_clk_ctl.s.enable = 0; + /* + * 2b. Select the USB reference clock/crystal parameters by writing + * appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON] + */ + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) { + /* + * The USB port uses 12/24/48MHz 2.5V board clock + * source at USB_XO. USB_XI should be tied to GND. + * Most Octeon evaluation boards require this setting + */ + if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || + OCTEON_IS_MODEL(OCTEON_CN56XX) || + OCTEON_IS_MODEL(OCTEON_CN50XX)) + /* From CN56XX,CN50XX,CN31XX,CN30XX manuals */ + usbn_clk_ctl.s.p_rtype = 2; /* p_rclk=1 & p_xenbn=0 */ + else + /* From CN52XX manual */ + usbn_clk_ctl.s.p_rtype = 1; + + switch (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) { + case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ: + usbn_clk_ctl.s.p_c_sel = 0; + break; + case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ: + usbn_clk_ctl.s.p_c_sel = 1; + break; + case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ: + usbn_clk_ctl.s.p_c_sel = 2; + break; + } + } else { + /* + * The USB port uses a 12MHz crystal as clock source + * at USB_XO and USB_XI + */ + if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) + /* From CN31XX,CN30XX manual */ + usbn_clk_ctl.s.p_rtype = 3; /* p_rclk=1 & p_xenbn=1 */ + else + /* From CN56XX,CN52XX,CN50XX manuals. */ + usbn_clk_ctl.s.p_rtype = 0; + + usbn_clk_ctl.s.p_c_sel = 0; + } + /* + * 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and + * setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down + * such that USB is as close as possible to 125Mhz + */ + { + int divisor = (octeon_get_clock_rate()+125000000-1)/125000000; + /* Lower than 4 doesn't seem to work properly */ + if (divisor < 4) + divisor = 4; + usbn_clk_ctl.s.divide = divisor; + usbn_clk_ctl.s.divide2 = 0; + } + __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), + usbn_clk_ctl.u64); + /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */ + usbn_clk_ctl.s.hclk_rst = 1; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), + usbn_clk_ctl.u64); + /* 2e. Wait 64 core-clock cycles for HCLK to stabilize */ + cvmx_wait(64); + /* + * 3. Program the power-on reset field in the USBN clock-control + * register: + * USBN_CLK_CTL[POR] = 0 + */ + usbn_clk_ctl.s.por = 0; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), + usbn_clk_ctl.u64); + /* 4. Wait 1 ms for PHY clock to start */ + mdelay(1); + /* + * 5. Program the Reset input from automatic test equipment field in the + * USBP control and status register: + * USBN_USBP_CTL_STATUS[ATE_RESET] = 1 + */ + usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index)); + usbn_usbp_ctl_status.s.ate_reset = 1; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), + usbn_usbp_ctl_status.u64); + /* 6. Wait 10 cycles */ + cvmx_wait(10); + /* + * 7. Clear ATE_RESET field in the USBN clock-control register: + * USBN_USBP_CTL_STATUS[ATE_RESET] = 0 + */ + usbn_usbp_ctl_status.s.ate_reset = 0; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), + usbn_usbp_ctl_status.u64); + /* + * 8. Program the PHY reset field in the USBN clock-control register: + * USBN_CLK_CTL[PRST] = 1 + */ + usbn_clk_ctl.s.prst = 1; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), + usbn_clk_ctl.u64); + /* + * 9. Program the USBP control and status register to select host or + * device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for + * device + */ + usbn_usbp_ctl_status.s.hst_mode = 0; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index), + usbn_usbp_ctl_status.u64); + /* 10. Wait 1 us */ + udelay(1); + /* + * 11. Program the hreset_n field in the USBN clock-control register: + * USBN_CLK_CTL[HRST] = 1 + */ + usbn_clk_ctl.s.hrst = 1; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), + usbn_clk_ctl.u64); + /* 12. Proceed to USB core initialization */ + usbn_clk_ctl.s.enable = 1; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), + usbn_clk_ctl.u64); + udelay(1); + + /* + * USB Core Initialization + * + * 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to + * determine USB core configuration parameters. + * + * Nothing needed + * + * 2. Program the following fields in the global AHB configuration + * register (USBC_GAHBCFG) + * DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode + * Burst length, USBC_GAHBCFG[HBSTLEN] = 0 + * Nonperiodic TxFIFO empty level (slave mode only), + * USBC_GAHBCFG[NPTXFEMPLVL] + * Periodic TxFIFO empty level (slave mode only), + * USBC_GAHBCFG[PTXFEMPLVL] + * Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 + */ + { + union cvmx_usbcx_gahbcfg usbcx_gahbcfg; + /* Due to an errata, CN31XX doesn't support DMA */ + if (OCTEON_IS_MODEL(OCTEON_CN31XX)) + usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA; + usbcx_gahbcfg.u32 = 0; + usbcx_gahbcfg.s.dmaen = !(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA); + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) + /* Only use one channel with non DMA */ + usb->idle_hardware_channels = 0x1; + else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) + /* CN5XXX have an errata with channel 3 */ + usb->idle_hardware_channels = 0xf7; + else + usb->idle_hardware_channels = 0xff; + usbcx_gahbcfg.s.hbstlen = 0; + usbcx_gahbcfg.s.nptxfemplvl = 1; + usbcx_gahbcfg.s.ptxfemplvl = 1; + usbcx_gahbcfg.s.glblintrmsk = 1; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index), + usbcx_gahbcfg.u32); + } + /* + * 3. Program the following fields in USBC_GUSBCFG register. + * HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0 + * ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0 + * USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5 + * PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0 + */ + { + union cvmx_usbcx_gusbcfg usbcx_gusbcfg; + usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index)); + usbcx_gusbcfg.s.toutcal = 0; + usbcx_gusbcfg.s.ddrsel = 0; + usbcx_gusbcfg.s.usbtrdtim = 0x5; + usbcx_gusbcfg.s.phylpwrclksel = 0; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index), + usbcx_gusbcfg.u32); + } + /* + * 4. The software must unmask the following bits in the USBC_GINTMSK + * register. + * OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1 + * Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1 + */ + { + union cvmx_usbcx_gintmsk usbcx_gintmsk; + int channel; + + usbcx_gintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index)); + usbcx_gintmsk.s.otgintmsk = 1; + usbcx_gintmsk.s.modemismsk = 1; + usbcx_gintmsk.s.hchintmsk = 1; + usbcx_gintmsk.s.sofmsk = 0; + /* We need RX FIFO interrupts if we don't have DMA */ + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) + usbcx_gintmsk.s.rxflvlmsk = 1; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index), + usbcx_gintmsk.u32); + + /* + * Disable all channel interrupts. We'll enable them per channel + * later. + */ + for (channel = 0; channel < 8; channel++) + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0); + } + + { + /* + * Host Port Initialization + * + * 1. Program the host-port interrupt-mask field to unmask, + * USBC_GINTMSK[PRTINT] = 1 + */ + USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, + prtintmsk, 1); + USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, + disconnintmsk, 1); + /* + * 2. Program the USBC_HCFG register to select full-speed host + * or high-speed host. + */ + { + union cvmx_usbcx_hcfg usbcx_hcfg; + usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index)); + usbcx_hcfg.s.fslssupp = 0; + usbcx_hcfg.s.fslspclksel = 0; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32); + } + /* + * 3. Program the port power bit to drive VBUS on the USB, + * USBC_HPRT[PRTPWR] = 1 + */ + USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtpwr, 1); + + /* + * Steps 4-15 from the manual are done later in the port enable + */ + } - hcd->state = HC_STATE_RUNNING; - spin_lock_irqsave(&priv->lock, flags); - cvmx_usb_register_callback(&priv->usb, CVMX_USB_CALLBACK_PORT_CHANGED, - octeon_usb_port_callback, NULL); - spin_unlock_irqrestore(&priv->lock, flags); return 0; } -static void octeon_usb_stop(struct usb_hcd *hcd) + +/** + * Shutdown a USB port after a call to cvmx_usb_initialize(). + * The port should be disabled with all pipes closed when this + * function is called. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * + * Returns: 0 or a negative error code. + */ +static int cvmx_usb_shutdown(struct cvmx_usb_state *usb) { - struct octeon_hcd *priv = hcd_to_octeon(hcd); - unsigned long flags; + union cvmx_usbnx_clk_ctl usbn_clk_ctl; + + /* Make sure all pipes are closed */ + if (!list_empty(&usb->idle_pipes) || + !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS]) || + !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT]) || + !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_CONTROL]) || + !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_BULK])) + return -EBUSY; + + /* Disable the clocks and put them in power on reset */ + usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index)); + usbn_clk_ctl.s.enable = 1; + usbn_clk_ctl.s.por = 1; + usbn_clk_ctl.s.hclk_rst = 1; + usbn_clk_ctl.s.prst = 0; + usbn_clk_ctl.s.hrst = 0; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index), + usbn_clk_ctl.u64); + return 0; +} - spin_lock_irqsave(&priv->lock, flags); - cvmx_usb_register_callback(&priv->usb, CVMX_USB_CALLBACK_PORT_CHANGED, - NULL, NULL); - spin_unlock_irqrestore(&priv->lock, flags); - hcd->state = HC_STATE_HALT; + +/** + * Enable a USB port. After this call succeeds, the USB port is + * online and servicing requests. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * + * Returns: 0 or a negative error code. + */ +static int cvmx_usb_enable(struct cvmx_usb_state *usb) +{ + union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3; + + usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); + + /* + * If the port is already enabled the just return. We don't need to do + * anything + */ + if (usb->usbcx_hprt.s.prtena) + return 0; + + /* If there is nothing plugged into the port then fail immediately */ + if (!usb->usbcx_hprt.s.prtconnsts) { + return -ETIMEDOUT; + } + + /* Program the port reset bit to start the reset process */ + USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 1); + + /* + * Wait at least 50ms (high speed), or 10ms (full speed) for the reset + * process to complete. + */ + mdelay(50); + + /* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */ + USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 0); + + /* Wait for the USBC_HPRT[PRTENA]. */ + if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, + prtena, ==, 1, 100000)) + return -ETIMEDOUT; + + /* + * Read the port speed field to get the enumerated speed, + * USBC_HPRT[PRTSPD]. + */ + usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); + usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index)); + + /* + * 13. Program the USBC_GRXFSIZ register to select the size of the + * receive FIFO (25%). + */ + USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), union cvmx_usbcx_grxfsiz, + rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4); + /* + * 14. Program the USBC_GNPTXFSIZ register to select the size and the + * start address of the non- periodic transmit FIFO for nonperiodic + * transactions (50%). + */ + { + union cvmx_usbcx_gnptxfsiz siz; + siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index)); + siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2; + siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32); + } + /* + * 15. Program the USBC_HPTXFSIZ register to select the size and start + * address of the periodic transmit FIFO for periodic transactions + * (25%). + */ + { + union cvmx_usbcx_hptxfsiz siz; + siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index)); + siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4; + siz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), siz.u32); + } + /* Flush all FIFOs */ + USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfnum, 0x10); + USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfflsh, 1); + CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, + txfflsh, ==, 0, 100); + USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, rxfflsh, 1); + CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, + rxfflsh, ==, 0, 100); + + return 0; } -static int octeon_usb_get_frame_number(struct usb_hcd *hcd) + +/** + * Disable a USB port. After this call the USB port will not + * generate data transfers and will not generate events. + * Transactions in process will fail and call their + * associated callbacks. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * + * Returns: 0 or a negative error code. + */ +static int cvmx_usb_disable(struct cvmx_usb_state *usb) { - struct octeon_hcd *priv = hcd_to_octeon(hcd); + /* Disable the port */ + USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtena, 1); + return 0; +} - return cvmx_usb_get_frame_number(&priv->usb); + +/** + * Get the current state of the USB port. Use this call to + * determine if the usb port has anything connected, is enabled, + * or has some sort of error condition. The return value of this + * call has "changed" bits to signal of the value of some fields + * have changed between calls. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * + * Returns: Port status information + */ +static struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *usb) +{ + union cvmx_usbcx_hprt usbc_hprt; + struct cvmx_usb_port_status result; + + memset(&result, 0, sizeof(result)); + + usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); + result.port_enabled = usbc_hprt.s.prtena; + result.port_over_current = usbc_hprt.s.prtovrcurract; + result.port_powered = usbc_hprt.s.prtpwr; + result.port_speed = usbc_hprt.s.prtspd; + result.connected = usbc_hprt.s.prtconnsts; + result.connect_change = (result.connected != usb->port_status.connected); + + return result; +} + +/** + * Open a virtual pipe between the host and a USB device. A pipe + * must be opened before data can be transferred between a device + * and Octeon. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @device_addr: + * USB device address to open the pipe to + * (0-127). + * @endpoint_num: + * USB endpoint number to open the pipe to + * (0-15). + * @device_speed: + * The speed of the device the pipe is going + * to. This must match the device's speed, + * which may be different than the port speed. + * @max_packet: The maximum packet length the device can + * transmit/receive (low speed=0-8, full + * speed=0-1023, high speed=0-1024). This value + * comes from the standard endpoint descriptor + * field wMaxPacketSize bits <10:0>. + * @transfer_type: + * The type of transfer this pipe is for. + * @transfer_dir: + * The direction the pipe is in. This is not + * used for control pipes. + * @interval: For ISOCHRONOUS and INTERRUPT transfers, + * this is how often the transfer is scheduled + * for. All other transfers should specify + * zero. The units are in frames (8000/sec at + * high speed, 1000/sec for full speed). + * @multi_count: + * For high speed devices, this is the maximum + * allowed number of packet per microframe. + * Specify zero for non high speed devices. This + * value comes from the standard endpoint descriptor + * field wMaxPacketSize bits <12:11>. + * @hub_device_addr: + * Hub device address this device is connected + * to. Devices connected directly to Octeon + * use zero. This is only used when the device + * is full/low speed behind a high speed hub. + * The address will be of the high speed hub, + * not and full speed hubs after it. + * @hub_port: Which port on the hub the device is + * connected. Use zero for devices connected + * directly to Octeon. Like hub_device_addr, + * this is only used for full/low speed + * devices behind a high speed hub. + * + * Returns: A non-NULL value is a pipe. NULL means an error. + */ +static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb, + int device_addr, int + endpoint_num, + enum cvmx_usb_speed + device_speed, + int max_packet, + enum cvmx_usb_transfer + transfer_type, + enum cvmx_usb_direction + transfer_dir, + int interval, int multi_count, + int hub_device_addr, + int hub_port) +{ + struct cvmx_usb_pipe *pipe; + + if (unlikely((device_addr < 0) || (device_addr > MAX_USB_ADDRESS))) + return NULL; + if (unlikely((endpoint_num < 0) || (endpoint_num > MAX_USB_ENDPOINT))) + return NULL; + if (unlikely(device_speed > CVMX_USB_SPEED_LOW)) + return NULL; + if (unlikely((max_packet <= 0) || (max_packet > 1024))) + return NULL; + if (unlikely(transfer_type > CVMX_USB_TRANSFER_INTERRUPT)) + return NULL; + if (unlikely((transfer_dir != CVMX_USB_DIRECTION_OUT) && + (transfer_dir != CVMX_USB_DIRECTION_IN))) + return NULL; + if (unlikely(interval < 0)) + return NULL; + if (unlikely((transfer_type == CVMX_USB_TRANSFER_CONTROL) && interval)) + return NULL; + if (unlikely(multi_count < 0)) + return NULL; + if (unlikely((device_speed != CVMX_USB_SPEED_HIGH) && + (multi_count != 0))) + return NULL; + if (unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS))) + return NULL; + if (unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT))) + return NULL; + + pipe = kzalloc(sizeof(*pipe), GFP_ATOMIC); + if (!pipe) + return NULL; + if ((device_speed == CVMX_USB_SPEED_HIGH) && + (transfer_dir == CVMX_USB_DIRECTION_OUT) && + (transfer_type == CVMX_USB_TRANSFER_BULK)) + pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING; + pipe->device_addr = device_addr; + pipe->endpoint_num = endpoint_num; + pipe->device_speed = device_speed; + pipe->max_packet = max_packet; + pipe->transfer_type = transfer_type; + pipe->transfer_dir = transfer_dir; + INIT_LIST_HEAD(&pipe->transactions); + + /* + * All pipes use interval to rate limit NAK processing. Force an + * interval if one wasn't supplied + */ + if (!interval) + interval = 1; + if (__cvmx_usb_pipe_needs_split(usb, pipe)) { + pipe->interval = interval*8; + /* Force start splits to be schedule on uFrame 0 */ + pipe->next_tx_frame = ((usb->frame_number+7)&~7) + pipe->interval; + } else { + pipe->interval = interval; + pipe->next_tx_frame = usb->frame_number + pipe->interval; + } + pipe->multi_count = multi_count; + pipe->hub_device_addr = hub_device_addr; + pipe->hub_port = hub_port; + pipe->pid_toggle = 0; + pipe->split_sc_frame = -1; + list_add_tail(&pipe->node, &usb->idle_pipes); + + /* + * We don't need to tell the hardware about this pipe yet since + * it doesn't have any submitted requests + */ + + return pipe; +} + + +/** + * Poll the RX FIFOs and remove data as needed. This function is only used + * in non DMA mode. It is very important that this function be called quickly + * enough to prevent FIFO overflow. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + */ +static void __cvmx_usb_poll_rx_fifo(struct cvmx_usb_state *usb) +{ + union cvmx_usbcx_grxstsph rx_status; + int channel; + int bytes; + uint64_t address; + uint32_t *ptr; + + rx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GRXSTSPH(usb->index)); + /* Only read data if IN data is there */ + if (rx_status.s.pktsts != 2) + return; + /* Check if no data is available */ + if (!rx_status.s.bcnt) + return; + + channel = rx_status.s.chnum; + bytes = rx_status.s.bcnt; + if (!bytes) + return; + + /* Get where the DMA engine would have written this data */ + address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8); + ptr = cvmx_phys_to_ptr(address); + __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, address + bytes); + + /* Loop writing the FIFO data for this packet into memory */ + while (bytes > 0) { + *ptr++ = __cvmx_usb_read_csr32(usb, USB_FIFO_ADDRESS(channel, usb->index)); + bytes -= 4; + } + CVMX_SYNCW; + + return; +} + + +/** + * Fill the TX hardware fifo with data out of the software + * fifos + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @fifo: Software fifo to use + * @available: Amount of space in the hardware fifo + * + * Returns: Non zero if the hardware fifo was too small and needs + * to be serviced again. + */ +static int __cvmx_usb_fill_tx_hw(struct cvmx_usb_state *usb, + struct cvmx_usb_tx_fifo *fifo, int available) +{ + /* + * We're done either when there isn't anymore space or the software FIFO + * is empty + */ + while (available && (fifo->head != fifo->tail)) { + int i = fifo->tail; + const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address); + uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel, usb->index) ^ 4; + int words = available; + + /* Limit the amount of data to waht the SW fifo has */ + if (fifo->entry[i].size <= available) { + words = fifo->entry[i].size; + fifo->tail++; + if (fifo->tail > MAX_CHANNELS) + fifo->tail = 0; + } + + /* Update the next locations and counts */ + available -= words; + fifo->entry[i].address += words * 4; + fifo->entry[i].size -= words; + + /* + * Write the HW fifo data. The read every three writes is due + * to an errata on CN3XXX chips + */ + while (words > 3) { + cvmx_write64_uint32(csr_address, *ptr++); + cvmx_write64_uint32(csr_address, *ptr++); + cvmx_write64_uint32(csr_address, *ptr++); + cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); + words -= 3; + } + cvmx_write64_uint32(csr_address, *ptr++); + if (--words) { + cvmx_write64_uint32(csr_address, *ptr++); + if (--words) + cvmx_write64_uint32(csr_address, *ptr++); + } + cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index)); + } + return fifo->head != fifo->tail; +} + + +/** + * Check the hardware FIFOs and fill them as needed + * + * @usb: USB device state populated by cvmx_usb_initialize(). + */ +static void __cvmx_usb_poll_tx_fifo(struct cvmx_usb_state *usb) +{ + if (usb->periodic.head != usb->periodic.tail) { + union cvmx_usbcx_hptxsts tx_status; + tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXSTS(usb->index)); + if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic, tx_status.s.ptxfspcavail)) + USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 1); + else + USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 0); + } + + if (usb->nonperiodic.head != usb->nonperiodic.tail) { + union cvmx_usbcx_gnptxsts tx_status; + tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXSTS(usb->index)); + if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, tx_status.s.nptxfspcavail)) + USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 1); + else + USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 0); + } + + return; +} + + +/** + * Fill the TX FIFO with an outgoing packet + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @channel: Channel number to get packet from + */ +static void __cvmx_usb_fill_tx_fifo(struct cvmx_usb_state *usb, int channel) +{ + union cvmx_usbcx_hccharx hcchar; + union cvmx_usbcx_hcspltx usbc_hcsplt; + union cvmx_usbcx_hctsizx usbc_hctsiz; + struct cvmx_usb_tx_fifo *fifo; + + /* We only need to fill data on outbound channels */ + hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index)); + if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT) + return; + + /* OUT Splits only have data on the start and not the complete */ + usbc_hcsplt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index)); + if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt) + return; + + /* + * Find out how many bytes we need to fill and convert it into 32bit + * words. + */ + usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index)); + if (!usbc_hctsiz.s.xfersize) + return; + + if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) || + (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS)) + fifo = &usb->periodic; + else + fifo = &usb->nonperiodic; + + fifo->entry[fifo->head].channel = channel; + fifo->entry[fifo->head].address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8); + fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize+3)>>2; + fifo->head++; + if (fifo->head > MAX_CHANNELS) + fifo->head = 0; + + __cvmx_usb_poll_tx_fifo(usb); + + return; +} + +/** + * Perform channel specific setup for Control transactions. All + * the generic stuff will already have been done in + * __cvmx_usb_start_channel() + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @channel: Channel to setup + * @pipe: Pipe for control transaction + */ +static void __cvmx_usb_start_channel_control(struct cvmx_usb_state *usb, + int channel, + struct cvmx_usb_pipe *pipe) +{ + struct cvmx_usb_transaction *transaction = + list_first_entry(&pipe->transactions, typeof(*transaction), + node); + union cvmx_usb_control_header *header = + cvmx_phys_to_ptr(transaction->control_header); + int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes; + int packets_to_transfer; + union cvmx_usbcx_hctsizx usbc_hctsiz; + + usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index)); + + switch (transaction->stage) { + case CVMX_USB_STAGE_NON_CONTROL: + case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE: + cvmx_dprintf("%s: ERROR - Non control stage\n", __FUNCTION__); + break; + case CVMX_USB_STAGE_SETUP: + usbc_hctsiz.s.pid = 3; /* Setup */ + bytes_to_transfer = sizeof(*header); + /* All Control operations start with a setup going OUT */ + USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT); + /* + * Setup send the control header instead of the buffer data. The + * buffer data will be used in the next stage + */ + __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header); + break; + case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE: + usbc_hctsiz.s.pid = 3; /* Setup */ + bytes_to_transfer = 0; + /* All Control operations start with a setup going OUT */ + USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT); + USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1); + break; + case CVMX_USB_STAGE_DATA: + usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); + if (__cvmx_usb_pipe_needs_split(usb, pipe)) { + if (header->s.request_type & 0x80) + bytes_to_transfer = 0; + else if (bytes_to_transfer > pipe->max_packet) + bytes_to_transfer = pipe->max_packet; + } + USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), + union cvmx_usbcx_hccharx, epdir, + ((header->s.request_type & 0x80) ? + CVMX_USB_DIRECTION_IN : + CVMX_USB_DIRECTION_OUT)); + break; + case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE: + usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); + if (!(header->s.request_type & 0x80)) + bytes_to_transfer = 0; + USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), + union cvmx_usbcx_hccharx, epdir, + ((header->s.request_type & 0x80) ? + CVMX_USB_DIRECTION_IN : + CVMX_USB_DIRECTION_OUT)); + USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1); + break; + case CVMX_USB_STAGE_STATUS: + usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); + bytes_to_transfer = 0; + USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, + ((header->s.request_type & 0x80) ? + CVMX_USB_DIRECTION_OUT : + CVMX_USB_DIRECTION_IN)); + break; + case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE: + usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); + bytes_to_transfer = 0; + USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, + ((header->s.request_type & 0x80) ? + CVMX_USB_DIRECTION_OUT : + CVMX_USB_DIRECTION_IN)); + USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1); + break; + } + + /* + * Make sure the transfer never exceeds the byte limit of the hardware. + * Further bytes will be sent as continued transactions + */ + if (bytes_to_transfer > MAX_TRANSFER_BYTES) { + /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */ + bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet; + bytes_to_transfer *= pipe->max_packet; + } + + /* + * Calculate the number of packets to transfer. If the length is zero + * we still need to transfer one packet + */ + packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet; + if (packets_to_transfer == 0) + packets_to_transfer = 1; + else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) { + /* + * Limit to one packet when not using DMA. Channels must be + * restarted between every packet for IN transactions, so there + * is no reason to do multiple packets in a row + */ + packets_to_transfer = 1; + bytes_to_transfer = packets_to_transfer * pipe->max_packet; + } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) { + /* + * Limit the number of packet and data transferred to what the + * hardware can handle + */ + packets_to_transfer = MAX_TRANSFER_PACKETS; + bytes_to_transfer = packets_to_transfer * pipe->max_packet; + } + + usbc_hctsiz.s.xfersize = bytes_to_transfer; + usbc_hctsiz.s.pktcnt = packets_to_transfer; + + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32); + return; +} + + +/** + * Start a channel to perform the pipe's head transaction + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @channel: Channel to setup + * @pipe: Pipe to start + */ +static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb, + int channel, + struct cvmx_usb_pipe *pipe) +{ + struct cvmx_usb_transaction *transaction = + list_first_entry(&pipe->transactions, typeof(*transaction), + node); + + /* Make sure all writes to the DMA region get flushed */ + CVMX_SYNCW; + + /* Attach the channel to the pipe */ + usb->pipe_for_channel[channel] = pipe; + pipe->channel = channel; + pipe->flags |= __CVMX_USB_PIPE_FLAGS_SCHEDULED; + + /* Mark this channel as in use */ + usb->idle_hardware_channels &= ~(1<<channel); + + /* Enable the channel interrupt bits */ + { + union cvmx_usbcx_hcintx usbc_hcint; + union cvmx_usbcx_hcintmskx usbc_hcintmsk; + union cvmx_usbcx_haintmsk usbc_haintmsk; + + /* Clear all channel status bits */ + usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index)); + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index), usbc_hcint.u32); + + usbc_hcintmsk.u32 = 0; + usbc_hcintmsk.s.chhltdmsk = 1; + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { + /* + * Channels need these extra interrupts when we aren't + * in DMA mode. + */ + usbc_hcintmsk.s.datatglerrmsk = 1; + usbc_hcintmsk.s.frmovrunmsk = 1; + usbc_hcintmsk.s.bblerrmsk = 1; + usbc_hcintmsk.s.xacterrmsk = 1; + if (__cvmx_usb_pipe_needs_split(usb, pipe)) { + /* + * Splits don't generate xfercompl, so we need + * ACK and NYET. + */ + usbc_hcintmsk.s.nyetmsk = 1; + usbc_hcintmsk.s.ackmsk = 1; + } + usbc_hcintmsk.s.nakmsk = 1; + usbc_hcintmsk.s.stallmsk = 1; + usbc_hcintmsk.s.xfercomplmsk = 1; + } + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), usbc_hcintmsk.u32); + + /* Enable the channel interrupt to propagate */ + usbc_haintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index)); + usbc_haintmsk.s.haintmsk |= 1<<channel; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), usbc_haintmsk.u32); + } + + /* Setup the locations the DMA engines use */ + { + uint64_t dma_address = transaction->buffer + transaction->actual_bytes; + if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) + dma_address = transaction->buffer + transaction->iso_packets[0].offset + transaction->actual_bytes; + __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, dma_address); + __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, dma_address); + } + + /* Setup both the size of the transfer and the SPLIT characteristics */ + { + union cvmx_usbcx_hcspltx usbc_hcsplt = {.u32 = 0}; + union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = 0}; + int packets_to_transfer; + int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes; + + /* + * ISOCHRONOUS transactions store each individual transfer size + * in the packet structure, not the global buffer_length + */ + if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) + bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes; + + /* + * We need to do split transactions when we are talking to non + * high speed devices that are behind a high speed hub + */ + if (__cvmx_usb_pipe_needs_split(usb, pipe)) { + /* + * On the start split phase (stage is even) record the + * frame number we will need to send the split complete. + * We only store the lower two bits since the time ahead + * can only be two frames + */ + if ((transaction->stage&1) == 0) { + if (transaction->type == CVMX_USB_TRANSFER_BULK) + pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f; + else + pipe->split_sc_frame = (usb->frame_number + 2) & 0x7f; + } else + pipe->split_sc_frame = -1; + + usbc_hcsplt.s.spltena = 1; + usbc_hcsplt.s.hubaddr = pipe->hub_device_addr; + usbc_hcsplt.s.prtaddr = pipe->hub_port; + usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE); + + /* + * SPLIT transactions can only ever transmit one data + * packet so limit the transfer size to the max packet + * size + */ + if (bytes_to_transfer > pipe->max_packet) + bytes_to_transfer = pipe->max_packet; + + /* + * ISOCHRONOUS OUT splits are unique in that they limit + * data transfers to 188 byte chunks representing the + * begin/middle/end of the data or all + */ + if (!usbc_hcsplt.s.compsplt && + (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) && + (pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) { + /* + * Clear the split complete frame number as + * there isn't going to be a split complete + */ + pipe->split_sc_frame = -1; + /* + * See if we've started this transfer and sent + * data + */ + if (transaction->actual_bytes == 0) { + /* + * Nothing sent yet, this is either a + * begin or the entire payload + */ + if (bytes_to_transfer <= 188) + /* Entire payload in one go */ + usbc_hcsplt.s.xactpos = 3; + else + /* First part of payload */ + usbc_hcsplt.s.xactpos = 2; + } else { + /* + * Continuing the previous data, we must + * either be in the middle or at the end + */ + if (bytes_to_transfer <= 188) + /* End of payload */ + usbc_hcsplt.s.xactpos = 1; + else + /* Middle of payload */ + usbc_hcsplt.s.xactpos = 0; + } + /* + * Again, the transfer size is limited to 188 + * bytes + */ + if (bytes_to_transfer > 188) + bytes_to_transfer = 188; + } + } + + /* + * Make sure the transfer never exceeds the byte limit of the + * hardware. Further bytes will be sent as continued + * transactions + */ + if (bytes_to_transfer > MAX_TRANSFER_BYTES) { + /* + * Round MAX_TRANSFER_BYTES to a multiple of out packet + * size + */ + bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet; + bytes_to_transfer *= pipe->max_packet; + } + + /* + * Calculate the number of packets to transfer. If the length is + * zero we still need to transfer one packet + */ + packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet; + if (packets_to_transfer == 0) + packets_to_transfer = 1; + else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) { + /* + * Limit to one packet when not using DMA. Channels must + * be restarted between every packet for IN + * transactions, so there is no reason to do multiple + * packets in a row + */ + packets_to_transfer = 1; + bytes_to_transfer = packets_to_transfer * pipe->max_packet; + } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) { + /* + * Limit the number of packet and data transferred to + * what the hardware can handle + */ + packets_to_transfer = MAX_TRANSFER_PACKETS; + bytes_to_transfer = packets_to_transfer * pipe->max_packet; + } + + usbc_hctsiz.s.xfersize = bytes_to_transfer; + usbc_hctsiz.s.pktcnt = packets_to_transfer; + + /* Update the DATA0/DATA1 toggle */ + usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe); + /* + * High speed pipes may need a hardware ping before they start + */ + if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING) + usbc_hctsiz.s.dopng = 1; + + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index), usbc_hcsplt.u32); + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32); + } + + /* Setup the Host Channel Characteristics Register */ + { + union cvmx_usbcx_hccharx usbc_hcchar = {.u32 = 0}; + + /* + * Set the startframe odd/even properly. This is only used for + * periodic + */ + usbc_hcchar.s.oddfrm = usb->frame_number&1; + + /* + * Set the number of back to back packets allowed by this + * endpoint. Split transactions interpret "ec" as the number of + * immediate retries of failure. These retries happen too + * quickly, so we disable these entirely for splits + */ + if (__cvmx_usb_pipe_needs_split(usb, pipe)) + usbc_hcchar.s.ec = 1; + else if (pipe->multi_count < 1) + usbc_hcchar.s.ec = 1; + else if (pipe->multi_count > 3) + usbc_hcchar.s.ec = 3; + else + usbc_hcchar.s.ec = pipe->multi_count; + + /* Set the rest of the endpoint specific settings */ + usbc_hcchar.s.devaddr = pipe->device_addr; + usbc_hcchar.s.eptype = transaction->type; + usbc_hcchar.s.lspddev = (pipe->device_speed == CVMX_USB_SPEED_LOW); + usbc_hcchar.s.epdir = pipe->transfer_dir; + usbc_hcchar.s.epnum = pipe->endpoint_num; + usbc_hcchar.s.mps = pipe->max_packet; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32); + } + + /* Do transaction type specific fixups as needed */ + switch (transaction->type) { + case CVMX_USB_TRANSFER_CONTROL: + __cvmx_usb_start_channel_control(usb, channel, pipe); + break; + case CVMX_USB_TRANSFER_BULK: + case CVMX_USB_TRANSFER_INTERRUPT: + break; + case CVMX_USB_TRANSFER_ISOCHRONOUS: + if (!__cvmx_usb_pipe_needs_split(usb, pipe)) { + /* + * ISO transactions require different PIDs depending on + * direction and how many packets are needed + */ + if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) { + if (pipe->multi_count < 2) /* Need DATA0 */ + USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 0); + else /* Need MDATA */ + USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 3); + } + } + break; + } + { + union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index))}; + transaction->xfersize = usbc_hctsiz.s.xfersize; + transaction->pktcnt = usbc_hctsiz.s.pktcnt; + } + /* Remeber when we start a split transaction */ + if (__cvmx_usb_pipe_needs_split(usb, pipe)) + usb->active_split = transaction; + USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, chena, 1); + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) + __cvmx_usb_fill_tx_fifo(usb, channel); + return; +} + + +/** + * Find a pipe that is ready to be scheduled to hardware. + * @usb: USB device state populated by cvmx_usb_initialize(). + * @list: Pipe list to search + * @current_frame: + * Frame counter to use as a time reference. + * + * Returns: Pipe or NULL if none are ready + */ +static struct cvmx_usb_pipe *__cvmx_usb_find_ready_pipe(struct cvmx_usb_state *usb, struct list_head *list, uint64_t current_frame) +{ + struct cvmx_usb_pipe *pipe; + + list_for_each_entry(pipe, list, node) { + struct cvmx_usb_transaction *t = + list_first_entry(&pipe->transactions, typeof(*t), node); + if (!(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED) && t && + (pipe->next_tx_frame <= current_frame) && + ((pipe->split_sc_frame == -1) || ((((int)current_frame - (int)pipe->split_sc_frame) & 0x7f) < 0x40)) && + (!usb->active_split || (usb->active_split == t))) { + CVMX_PREFETCH(pipe, 128); + CVMX_PREFETCH(t, 0); + return pipe; + } + } + return NULL; +} + + +/** + * Called whenever a pipe might need to be scheduled to the + * hardware. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @is_sof: True if this schedule was called on a SOF interrupt. + */ +static void __cvmx_usb_schedule(struct cvmx_usb_state *usb, int is_sof) +{ + int channel; + struct cvmx_usb_pipe *pipe; + int need_sof; + enum cvmx_usb_transfer ttype; + + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { + /* + * Without DMA we need to be careful to not schedule something + * at the end of a frame and cause an overrun. + */ + union cvmx_usbcx_hfnum hfnum = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index))}; + union cvmx_usbcx_hfir hfir = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFIR(usb->index))}; + if (hfnum.s.frrem < hfir.s.frint/4) + goto done; + } + + while (usb->idle_hardware_channels) { + /* Find an idle channel */ + channel = __fls(usb->idle_hardware_channels); + if (unlikely(channel > 7)) + break; + + /* Find a pipe needing service */ + pipe = NULL; + if (is_sof) { + /* + * Only process periodic pipes on SOF interrupts. This + * way we are sure that the periodic data is sent in the + * beginning of the frame + */ + pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number); + if (likely(!pipe)) + pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number); + } + if (likely(!pipe)) { + pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_CONTROL, usb->frame_number); + if (likely(!pipe)) + pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_BULK, usb->frame_number); + } + if (!pipe) + break; + + __cvmx_usb_start_channel(usb, channel, pipe); + } + +done: + /* + * Only enable SOF interrupts when we have transactions pending in the + * future that might need to be scheduled + */ + need_sof = 0; + for (ttype = CVMX_USB_TRANSFER_CONTROL; ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) { + list_for_each_entry(pipe, &usb->active_pipes[ttype], node) { + if (pipe->next_tx_frame > usb->frame_number) { + need_sof = 1; + break; + } + } + } + USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, sofmsk, need_sof); + return; +} + +static inline struct octeon_hcd *cvmx_usb_to_octeon(struct cvmx_usb_state *p) +{ + return container_of(p, struct octeon_hcd, usb); +} + +static inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p) +{ + return container_of((void *)p, struct usb_hcd, hcd_priv); } static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb, - enum cvmx_usb_callback reason, enum cvmx_usb_complete status, - int pipe_handle, - int submit_handle, + struct cvmx_usb_pipe *pipe, + struct cvmx_usb_transaction + *transaction, int bytes_transferred, - void *user_data) + struct urb *urb) { struct octeon_hcd *priv = cvmx_usb_to_octeon(usb); struct usb_hcd *hcd = octeon_to_hcd(priv); struct device *dev = hcd->self.controller; - struct urb *urb = user_data; urb->actual_length = bytes_transferred; urb->hcpriv = NULL; - if (!list_empty(&urb->urb_list)) { + if (!list_empty(&urb->urb_list)) /* * It is on the dequeue_list, but we are going to call * usb_hcd_giveback_urb(), so we must clear it from * the list. We got to it before the * octeon_usb_urb_dequeue_work() tasklet did. */ - list_del(&urb->urb_list); - /* No longer on the dequeue_list. */ - INIT_LIST_HEAD(&urb->urb_list); - } + list_del_init(&urb->urb_list); /* For Isochronous transactions we need to update the URB packet status list from data in our private copy */ @@ -151,10 +2013,10 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb, urb->iso_frame_desc[i].actual_length = iso_packet[i].length; urb->actual_length += urb->iso_frame_desc[i].actual_length; } else { - dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%d submit=%d size=%d\n", + dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%p transaction=%p size=%d\n", i, urb->number_of_packets, - iso_packet[i].status, pipe_handle, - submit_handle, iso_packet[i].length); + iso_packet[i].status, pipe, + transaction, iso_packet[i].length); urb->iso_frame_desc[i].status = -EREMOTEIO; } } @@ -172,26 +2034,26 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb, urb->status = -ENOENT; break; case CVMX_USB_COMPLETE_STALL: - dev_dbg(dev, "status=stall pipe=%d submit=%d size=%d\n", - pipe_handle, submit_handle, bytes_transferred); + dev_dbg(dev, "status=stall pipe=%p transaction=%p size=%d\n", + pipe, transaction, bytes_transferred); urb->status = -EPIPE; break; case CVMX_USB_COMPLETE_BABBLEERR: - dev_dbg(dev, "status=babble pipe=%d submit=%d size=%d\n", - pipe_handle, submit_handle, bytes_transferred); + dev_dbg(dev, "status=babble pipe=%p transaction=%p size=%d\n", + pipe, transaction, bytes_transferred); urb->status = -EPIPE; break; case CVMX_USB_COMPLETE_SHORT: - dev_dbg(dev, "status=short pipe=%d submit=%d size=%d\n", - pipe_handle, submit_handle, bytes_transferred); + dev_dbg(dev, "status=short pipe=%p transaction=%p size=%d\n", + pipe, transaction, bytes_transferred); urb->status = -EREMOTEIO; break; case CVMX_USB_COMPLETE_ERROR: case CVMX_USB_COMPLETE_XACTERR: case CVMX_USB_COMPLETE_DATATGLERR: case CVMX_USB_COMPLETE_FRAMEERR: - dev_dbg(dev, "status=%d pipe=%d submit=%d size=%d\n", - status, pipe_handle, submit_handle, bytes_transferred); + dev_dbg(dev, "status=%d pipe=%p transaction=%p size=%d\n", + status, pipe, transaction, bytes_transferred); urb->status = -EPROTO; break; } @@ -200,14 +2062,952 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb, spin_lock(&priv->lock); } +/** + * Signal the completion of a transaction and free it. The + * transaction will be removed from the pipe transaction list. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @pipe: Pipe the transaction is on + * @transaction: + * Transaction that completed + * @complete_code: + * Completion code + */ +static void __cvmx_usb_perform_complete(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe, + struct cvmx_usb_transaction *transaction, + enum cvmx_usb_complete complete_code) +{ + /* If this was a split then clear our split in progress marker */ + if (usb->active_split == transaction) + usb->active_split = NULL; + + /* + * Isochronous transactions need extra processing as they might not be + * done after a single data transfer + */ + if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) { + /* Update the number of bytes transferred in this ISO packet */ + transaction->iso_packets[0].length = transaction->actual_bytes; + transaction->iso_packets[0].status = complete_code; + + /* + * If there are more ISOs pending and we succeeded, schedule the + * next one + */ + if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) { + /* No bytes transferred for this packet as of yet */ + transaction->actual_bytes = 0; + /* One less ISO waiting to transfer */ + transaction->iso_number_packets--; + /* Increment to the next location in our packet array */ + transaction->iso_packets++; + transaction->stage = CVMX_USB_STAGE_NON_CONTROL; + goto done; + } + } + + /* Remove the transaction from the pipe list */ + list_del(&transaction->node); + if (list_empty(&pipe->transactions)) + list_move_tail(&pipe->node, &usb->idle_pipes); + octeon_usb_urb_complete_callback(usb, complete_code, pipe, + transaction, + transaction->actual_bytes, + transaction->urb); + kfree(transaction); +done: + return; +} + + +/** + * Submit a usb transaction to a pipe. Called for all types + * of transactions. + * + * @usb: + * @pipe: Which pipe to submit to. + * @type: Transaction type + * @buffer: User buffer for the transaction + * @buffer_length: + * User buffer's length in bytes + * @control_header: + * For control transactions, the 8 byte standard header + * @iso_start_frame: + * For ISO transactions, the start frame + * @iso_number_packets: + * For ISO, the number of packet in the transaction. + * @iso_packets: + * A description of each ISO packet + * @urb: URB for the callback + * + * Returns: Transaction or NULL on failure. + */ +static struct cvmx_usb_transaction *__cvmx_usb_submit_transaction(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe, + enum cvmx_usb_transfer type, + uint64_t buffer, + int buffer_length, + uint64_t control_header, + int iso_start_frame, + int iso_number_packets, + struct cvmx_usb_iso_packet *iso_packets, + struct urb *urb) +{ + struct cvmx_usb_transaction *transaction; + + if (unlikely(pipe->transfer_type != type)) + return NULL; + + transaction = kzalloc(sizeof(*transaction), GFP_ATOMIC); + if (unlikely(!transaction)) + return NULL; + + transaction->type = type; + transaction->buffer = buffer; + transaction->buffer_length = buffer_length; + transaction->control_header = control_header; + /* FIXME: This is not used, implement it. */ + transaction->iso_start_frame = iso_start_frame; + transaction->iso_number_packets = iso_number_packets; + transaction->iso_packets = iso_packets; + transaction->urb = urb; + if (transaction->type == CVMX_USB_TRANSFER_CONTROL) + transaction->stage = CVMX_USB_STAGE_SETUP; + else + transaction->stage = CVMX_USB_STAGE_NON_CONTROL; + + if (!list_empty(&pipe->transactions)) { + list_add_tail(&transaction->node, &pipe->transactions); + } else { + list_add_tail(&transaction->node, &pipe->transactions); + list_move_tail(&pipe->node, + &usb->active_pipes[pipe->transfer_type]); + + /* + * We may need to schedule the pipe if this was the head of the + * pipe. + */ + __cvmx_usb_schedule(usb, 0); + } + + return transaction; +} + + +/** + * Call to submit a USB Bulk transfer to a pipe. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @pipe: Handle to the pipe for the transfer. + * @urb: URB. + * + * Returns: A submitted transaction or NULL on failure. + */ +static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe, + struct urb *urb) +{ + return __cvmx_usb_submit_transaction(usb, pipe, CVMX_USB_TRANSFER_BULK, + urb->transfer_dma, + urb->transfer_buffer_length, + 0, /* control_header */ + 0, /* iso_start_frame */ + 0, /* iso_number_packets */ + NULL, /* iso_packets */ + urb); +} + + +/** + * Call to submit a USB Interrupt transfer to a pipe. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @pipe: Handle to the pipe for the transfer. + * @urb: URB returned when the callback is called. + * + * Returns: A submitted transaction or NULL on failure. + */ +static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe, + struct urb *urb) +{ + return __cvmx_usb_submit_transaction(usb, pipe, + CVMX_USB_TRANSFER_INTERRUPT, + urb->transfer_dma, + urb->transfer_buffer_length, + 0, /* control_header */ + 0, /* iso_start_frame */ + 0, /* iso_number_packets */ + NULL, /* iso_packets */ + urb); +} + + +/** + * Call to submit a USB Control transfer to a pipe. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @pipe: Handle to the pipe for the transfer. + * @urb: URB. + * + * Returns: A submitted transaction or NULL on failure. + */ +static struct cvmx_usb_transaction *cvmx_usb_submit_control(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe, + struct urb *urb) +{ + int buffer_length = urb->transfer_buffer_length; + uint64_t control_header = urb->setup_dma; + union cvmx_usb_control_header *header = + cvmx_phys_to_ptr(control_header); + + if ((header->s.request_type & 0x80) == 0) + buffer_length = le16_to_cpu(header->s.length); + + return __cvmx_usb_submit_transaction(usb, pipe, + CVMX_USB_TRANSFER_CONTROL, + urb->transfer_dma, buffer_length, + control_header, + 0, /* iso_start_frame */ + 0, /* iso_number_packets */ + NULL, /* iso_packets */ + urb); +} + + +/** + * Call to submit a USB Isochronous transfer to a pipe. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @pipe: Handle to the pipe for the transfer. + * @urb: URB returned when the callback is called. + * + * Returns: A submitted transaction or NULL on failure. + */ +static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe, + struct urb *urb) +{ + struct cvmx_usb_iso_packet *packets; + + packets = (struct cvmx_usb_iso_packet *) urb->setup_packet; + return __cvmx_usb_submit_transaction(usb, pipe, + CVMX_USB_TRANSFER_ISOCHRONOUS, + urb->transfer_dma, + urb->transfer_buffer_length, + 0, /* control_header */ + urb->start_frame, + urb->number_of_packets, + packets, urb); +} + + +/** + * Cancel one outstanding request in a pipe. Canceling a request + * can fail if the transaction has already completed before cancel + * is called. Even after a successful cancel call, it may take + * a frame or two for the cvmx_usb_poll() function to call the + * associated callback. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @pipe: Pipe to cancel requests in. + * @transaction: Transaction to cancel, returned by the submit function. + * + * Returns: 0 or a negative error code. + */ +static int cvmx_usb_cancel(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe, + struct cvmx_usb_transaction *transaction) +{ + /* + * If the transaction is the HEAD of the queue and scheduled. We need to + * treat it special + */ + if (list_first_entry(&pipe->transactions, typeof(*transaction), node) == + transaction && (pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED)) { + union cvmx_usbcx_hccharx usbc_hcchar; + + usb->pipe_for_channel[pipe->channel] = NULL; + pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED; + + CVMX_SYNCW; + + usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index)); + /* + * If the channel isn't enabled then the transaction already + * completed. + */ + if (usbc_hcchar.s.chena) { + usbc_hcchar.s.chdis = 1; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index), usbc_hcchar.u32); + } + } + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_CANCEL); + return 0; +} + + +/** + * Cancel all outstanding requests in a pipe. Logically all this + * does is call cvmx_usb_cancel() in a loop. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @pipe: Pipe to cancel requests in. + * + * Returns: 0 or a negative error code. + */ +static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe) +{ + struct cvmx_usb_transaction *transaction, *next; + + /* Simply loop through and attempt to cancel each transaction */ + list_for_each_entry_safe(transaction, next, &pipe->transactions, node) { + int result = cvmx_usb_cancel(usb, pipe, transaction); + if (unlikely(result != 0)) + return result; + } + return 0; +} + + +/** + * Close a pipe created with cvmx_usb_open_pipe(). + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * @pipe: Pipe to close. + * + * Returns: 0 or a negative error code. EBUSY is returned if the pipe has + * outstanding transfers. + */ +static int cvmx_usb_close_pipe(struct cvmx_usb_state *usb, + struct cvmx_usb_pipe *pipe) +{ + /* Fail if the pipe has pending transactions */ + if (!list_empty(&pipe->transactions)) + return -EBUSY; + + list_del(&pipe->node); + kfree(pipe); + + return 0; +} + +/** + * Get the current USB protocol level frame number. The frame + * number is always in the range of 0-0x7ff. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * + * Returns: USB frame number + */ +static int cvmx_usb_get_frame_number(struct cvmx_usb_state *usb) +{ + int frame_number; + union cvmx_usbcx_hfnum usbc_hfnum; + + usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index)); + frame_number = usbc_hfnum.s.frnum; + + return frame_number; +} + + +/** + * Poll a channel for status + * + * @usb: USB device + * @channel: Channel to poll + * + * Returns: Zero on success + */ +static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel) +{ + union cvmx_usbcx_hcintx usbc_hcint; + union cvmx_usbcx_hctsizx usbc_hctsiz; + union cvmx_usbcx_hccharx usbc_hcchar; + struct cvmx_usb_pipe *pipe; + struct cvmx_usb_transaction *transaction; + int bytes_this_transfer; + int bytes_in_last_packet; + int packets_processed; + int buffer_space_left; + + /* Read the interrupt status bits for the channel */ + usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index)); + + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { + usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index)); + + if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) { + /* + * There seems to be a bug in CN31XX which can cause + * interrupt IN transfers to get stuck until we do a + * write of HCCHARX without changing things + */ + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32); + return 0; + } + + /* + * In non DMA mode the channels don't halt themselves. We need + * to manually disable channels that are left running + */ + if (!usbc_hcint.s.chhltd) { + if (usbc_hcchar.s.chena) { + union cvmx_usbcx_hcintmskx hcintmsk; + /* Disable all interrupts except CHHLTD */ + hcintmsk.u32 = 0; + hcintmsk.s.chhltdmsk = 1; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), hcintmsk.u32); + usbc_hcchar.s.chdis = 1; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32); + return 0; + } else if (usbc_hcint.s.xfercompl) { + /* + * Successful IN/OUT with transfer complete. + * Channel halt isn't needed. + */ + } else { + cvmx_dprintf("USB%d: Channel %d interrupt without halt\n", usb->index, channel); + return 0; + } + } + } else { + /* + * There is are no interrupts that we need to process when the + * channel is still running + */ + if (!usbc_hcint.s.chhltd) + return 0; + } + + /* Disable the channel interrupts now that it is done */ + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0); + usb->idle_hardware_channels |= (1<<channel); + + /* Make sure this channel is tied to a valid pipe */ + pipe = usb->pipe_for_channel[channel]; + CVMX_PREFETCH(pipe, 0); + CVMX_PREFETCH(pipe, 128); + if (!pipe) + return 0; + transaction = list_first_entry(&pipe->transactions, typeof(*transaction), + node); + CVMX_PREFETCH(transaction, 0); + + /* + * Disconnect this pipe from the HW channel. Later the schedule + * function will figure out which pipe needs to go + */ + usb->pipe_for_channel[channel] = NULL; + pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED; + + /* + * Read the channel config info so we can figure out how much data + * transfered + */ + usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index)); + usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index)); + + /* + * Calculating the number of bytes successfully transferred is dependent + * on the transfer direction + */ + packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt; + if (usbc_hcchar.s.epdir) { + /* + * IN transactions are easy. For every byte received the + * hardware decrements xfersize. All we need to do is subtract + * the current value of xfersize from its starting value and we + * know how many bytes were written to the buffer + */ + bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize; + } else { + /* + * OUT transaction don't decrement xfersize. Instead pktcnt is + * decremented on every successful packet send. The hardware + * does this when it receives an ACK, or NYET. If it doesn't + * receive one of these responses pktcnt doesn't change + */ + bytes_this_transfer = packets_processed * usbc_hcchar.s.mps; + /* + * The last packet may not be a full transfer if we didn't have + * enough data + */ + if (bytes_this_transfer > transaction->xfersize) + bytes_this_transfer = transaction->xfersize; + } + /* Figure out how many bytes were in the last packet of the transfer */ + if (packets_processed) + bytes_in_last_packet = bytes_this_transfer - (packets_processed-1) * usbc_hcchar.s.mps; + else + bytes_in_last_packet = bytes_this_transfer; + + /* + * As a special case, setup transactions output the setup header, not + * the user's data. For this reason we don't count setup data as bytes + * transferred + */ + if ((transaction->stage == CVMX_USB_STAGE_SETUP) || + (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE)) + bytes_this_transfer = 0; + + /* + * Add the bytes transferred to the running total. It is important that + * bytes_this_transfer doesn't count any data that needs to be + * retransmitted + */ + transaction->actual_bytes += bytes_this_transfer; + if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS) + buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes; + else + buffer_space_left = transaction->buffer_length - transaction->actual_bytes; + + /* + * We need to remember the PID toggle state for the next transaction. + * The hardware already updated it for the next transaction + */ + pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0); + + /* + * For high speed bulk out, assume the next transaction will need to do + * a ping before proceeding. If this isn't true the ACK processing below + * will clear this flag + */ + if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) && + (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) && + (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT)) + pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING; + + if (usbc_hcint.s.stall) { + /* + * STALL as a response means this transaction cannot be + * completed because the device can't process transactions. Tell + * the user. Any data that was transferred will be counted on + * the actual bytes transferred + */ + pipe->pid_toggle = 0; + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL); + } else if (usbc_hcint.s.xacterr) { + /* + * We know at least one packet worked if we get a ACK or NAK. + * Reset the retry counter + */ + if (usbc_hcint.s.nak || usbc_hcint.s.ack) + transaction->retries = 0; + transaction->retries++; + if (transaction->retries > MAX_RETRIES) { + /* + * XactErr as a response means the device signaled + * something wrong with the transfer. For example, PID + * toggle errors cause these + */ + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR); + } else { + /* + * If this was a split then clear our split in progress + * marker + */ + if (usb->active_split == transaction) + usb->active_split = NULL; + /* + * Rewind to the beginning of the transaction by anding + * off the split complete bit + */ + transaction->stage &= ~1; + pipe->split_sc_frame = -1; + pipe->next_tx_frame += pipe->interval; + if (pipe->next_tx_frame < usb->frame_number) + pipe->next_tx_frame = usb->frame_number + pipe->interval - + (usb->frame_number - pipe->next_tx_frame) % pipe->interval; + } + } else if (usbc_hcint.s.bblerr) { + /* Babble Error (BblErr) */ + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_BABBLEERR); + } else if (usbc_hcint.s.datatglerr) { + /* We'll retry the exact same transaction again */ + transaction->retries++; + } else if (usbc_hcint.s.nyet) { + /* + * NYET as a response is only allowed in three cases: as a + * response to a ping, as a response to a split transaction, and + * as a response to a bulk out. The ping case is handled by + * hardware, so we only have splits and bulk out + */ + if (!__cvmx_usb_pipe_needs_split(usb, pipe)) { + transaction->retries = 0; + /* + * If there is more data to go then we need to try + * again. Otherwise this transaction is complete + */ + if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); + } else { + /* + * Split transactions retry the split complete 4 times + * then rewind to the start split and do the entire + * transactions again + */ + transaction->retries++; + if ((transaction->retries & 0x3) == 0) { + /* + * Rewind to the beginning of the transaction by + * anding off the split complete bit + */ + transaction->stage &= ~1; + pipe->split_sc_frame = -1; + } + } + } else if (usbc_hcint.s.ack) { + transaction->retries = 0; + /* + * The ACK bit can only be checked after the other error bits. + * This is because a multi packet transfer may succeed in a + * number of packets and then get a different response on the + * last packet. In this case both ACK and the last response bit + * will be set. If none of the other response bits is set, then + * the last packet must have been an ACK + * + * Since we got an ACK, we know we don't need to do a ping on + * this pipe + */ + pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_NEED_PING; + + switch (transaction->type) { + case CVMX_USB_TRANSFER_CONTROL: + switch (transaction->stage) { + case CVMX_USB_STAGE_NON_CONTROL: + case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE: + /* This should be impossible */ + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR); + break; + case CVMX_USB_STAGE_SETUP: + pipe->pid_toggle = 1; + if (__cvmx_usb_pipe_needs_split(usb, pipe)) + transaction->stage = CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE; + else { + union cvmx_usb_control_header *header = + cvmx_phys_to_ptr(transaction->control_header); + if (header->s.length) + transaction->stage = CVMX_USB_STAGE_DATA; + else + transaction->stage = CVMX_USB_STAGE_STATUS; + } + break; + case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE: + { + union cvmx_usb_control_header *header = + cvmx_phys_to_ptr(transaction->control_header); + if (header->s.length) + transaction->stage = CVMX_USB_STAGE_DATA; + else + transaction->stage = CVMX_USB_STAGE_STATUS; + } + break; + case CVMX_USB_STAGE_DATA: + if (__cvmx_usb_pipe_needs_split(usb, pipe)) { + transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE; + /* + * For setup OUT data that are splits, + * the hardware doesn't appear to count + * transferred data. Here we manually + * update the data transferred + */ + if (!usbc_hcchar.s.epdir) { + if (buffer_space_left < pipe->max_packet) + transaction->actual_bytes += buffer_space_left; + else + transaction->actual_bytes += pipe->max_packet; + } + } else if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) { + pipe->pid_toggle = 1; + transaction->stage = CVMX_USB_STAGE_STATUS; + } + break; + case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE: + if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) { + pipe->pid_toggle = 1; + transaction->stage = CVMX_USB_STAGE_STATUS; + } else { + transaction->stage = CVMX_USB_STAGE_DATA; + } + break; + case CVMX_USB_STAGE_STATUS: + if (__cvmx_usb_pipe_needs_split(usb, pipe)) + transaction->stage = CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE; + else + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); + break; + case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE: + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); + break; + } + break; + case CVMX_USB_TRANSFER_BULK: + case CVMX_USB_TRANSFER_INTERRUPT: + /* + * The only time a bulk transfer isn't complete when it + * finishes with an ACK is during a split transaction. + * For splits we need to continue the transfer if more + * data is needed + */ + if (__cvmx_usb_pipe_needs_split(usb, pipe)) { + if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL) + transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE; + else { + if (buffer_space_left && (bytes_in_last_packet == pipe->max_packet)) + transaction->stage = CVMX_USB_STAGE_NON_CONTROL; + else { + if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT) + pipe->next_tx_frame += pipe->interval; + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); + } + } + } else { + if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) && + (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) && + (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) && + (usbc_hcint.s.nak)) + pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING; + if (!buffer_space_left || (bytes_in_last_packet < pipe->max_packet)) { + if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT) + pipe->next_tx_frame += pipe->interval; + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); + } + } + break; + case CVMX_USB_TRANSFER_ISOCHRONOUS: + if (__cvmx_usb_pipe_needs_split(usb, pipe)) { + /* + * ISOCHRONOUS OUT splits don't require a + * complete split stage. Instead they use a + * sequence of begin OUT splits to transfer the + * data 188 bytes at a time. Once the transfer + * is complete, the pipe sleeps until the next + * schedule interval + */ + if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) { + /* + * If no space left or this wasn't a max + * size packet then this transfer is + * complete. Otherwise start it again to + * send the next 188 bytes + */ + if (!buffer_space_left || (bytes_this_transfer < 188)) { + pipe->next_tx_frame += pipe->interval; + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); + } + } else { + if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) { + /* + * We are in the incoming data + * phase. Keep getting data + * until we run out of space or + * get a small packet + */ + if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) { + pipe->next_tx_frame += pipe->interval; + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); + } + } else + transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE; + } + } else { + pipe->next_tx_frame += pipe->interval; + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS); + } + break; + } + } else if (usbc_hcint.s.nak) { + /* + * If this was a split then clear our split in progress marker. + */ + if (usb->active_split == transaction) + usb->active_split = NULL; + /* + * NAK as a response means the device couldn't accept the + * transaction, but it should be retried in the future. Rewind + * to the beginning of the transaction by anding off the split + * complete bit. Retry in the next interval + */ + transaction->retries = 0; + transaction->stage &= ~1; + pipe->next_tx_frame += pipe->interval; + if (pipe->next_tx_frame < usb->frame_number) + pipe->next_tx_frame = usb->frame_number + pipe->interval - + (usb->frame_number - pipe->next_tx_frame) % pipe->interval; + } else { + struct cvmx_usb_port_status port; + port = cvmx_usb_get_status(usb); + if (port.port_enabled) { + /* We'll retry the exact same transaction again */ + transaction->retries++; + } else { + /* + * We get channel halted interrupts with no result bits + * sets when the cable is unplugged + */ + __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR); + } + } + return 0; +} + +static void octeon_usb_port_callback(struct cvmx_usb_state *usb) +{ + struct octeon_hcd *priv = cvmx_usb_to_octeon(usb); + + spin_unlock(&priv->lock); + usb_hcd_poll_rh_status(octeon_to_hcd(priv)); + spin_lock(&priv->lock); +} + +/** + * Poll the USB block for status and call all needed callback + * handlers. This function is meant to be called in the interrupt + * handler for the USB controller. It can also be called + * periodically in a loop for non-interrupt based operation. + * + * @usb: USB device state populated by cvmx_usb_initialize(). + * + * Returns: 0 or a negative error code. + */ +static int cvmx_usb_poll(struct cvmx_usb_state *usb) +{ + union cvmx_usbcx_hfnum usbc_hfnum; + union cvmx_usbcx_gintsts usbc_gintsts; + + CVMX_PREFETCH(usb, 0); + CVMX_PREFETCH(usb, 1*128); + CVMX_PREFETCH(usb, 2*128); + CVMX_PREFETCH(usb, 3*128); + CVMX_PREFETCH(usb, 4*128); + + /* Update the frame counter */ + usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index)); + if ((usb->frame_number&0x3fff) > usbc_hfnum.s.frnum) + usb->frame_number += 0x4000; + usb->frame_number &= ~0x3fffull; + usb->frame_number |= usbc_hfnum.s.frnum; + + /* Read the pending interrupts */ + usbc_gintsts.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index)); + + /* Clear the interrupts now that we know about them */ + __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32); + + if (usbc_gintsts.s.rxflvl) { + /* + * RxFIFO Non-Empty (RxFLvl) + * Indicates that there is at least one packet pending to be + * read from the RxFIFO. + * + * In DMA mode this is handled by hardware + */ + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) + __cvmx_usb_poll_rx_fifo(usb); + } + if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) { + /* Fill the Tx FIFOs when not in DMA mode */ + if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) + __cvmx_usb_poll_tx_fifo(usb); + } + if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) { + union cvmx_usbcx_hprt usbc_hprt; + /* + * Disconnect Detected Interrupt (DisconnInt) + * Asserted when a device disconnect is detected. + * + * Host Port Interrupt (PrtInt) + * The core sets this bit to indicate a change in port status of + * one of the O2P USB core ports in Host mode. The application + * must read the Host Port Control and Status (HPRT) register to + * determine the exact event that caused this interrupt. The + * application must clear the appropriate status bit in the Host + * Port Control and Status register to clear this bit. + * + * Call the user's port callback + */ + octeon_usb_port_callback(usb); + /* Clear the port change bits */ + usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index)); + usbc_hprt.s.prtena = 0; + __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32); + } + if (usbc_gintsts.s.hchint) { + /* + * Host Channels Interrupt (HChInt) + * The core sets this bit to indicate that an interrupt is + * pending on one of the channels of the core (in Host mode). + * The application must read the Host All Channels Interrupt + * (HAINT) register to determine the exact number of the channel + * on which the interrupt occurred, and then read the + * corresponding Host Channel-n Interrupt (HCINTn) register to + * determine the exact cause of the interrupt. The application + * must clear the appropriate status bit in the HCINTn register + * to clear this bit. + */ + union cvmx_usbcx_haint usbc_haint; + usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index)); + while (usbc_haint.u32) { + int channel; + + channel = __fls(usbc_haint.u32); + __cvmx_usb_poll_channel(usb, channel); + usbc_haint.u32 ^= 1<<channel; + } + } + + __cvmx_usb_schedule(usb, usbc_gintsts.s.sof); + + return 0; +} + +/* convert between an HCD pointer and the corresponding struct octeon_hcd */ +static inline struct octeon_hcd *hcd_to_octeon(struct usb_hcd *hcd) +{ + return (struct octeon_hcd *)(hcd->hcd_priv); +} + +static irqreturn_t octeon_usb_irq(struct usb_hcd *hcd) +{ + struct octeon_hcd *priv = hcd_to_octeon(hcd); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + cvmx_usb_poll(&priv->usb); + spin_unlock_irqrestore(&priv->lock, flags); + return IRQ_HANDLED; +} + +static int octeon_usb_start(struct usb_hcd *hcd) +{ + hcd->state = HC_STATE_RUNNING; + return 0; +} + +static void octeon_usb_stop(struct usb_hcd *hcd) +{ + hcd->state = HC_STATE_HALT; +} + +static int octeon_usb_get_frame_number(struct usb_hcd *hcd) +{ + struct octeon_hcd *priv = hcd_to_octeon(hcd); + + return cvmx_usb_get_frame_number(&priv->usb); +} + static int octeon_usb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) { struct octeon_hcd *priv = hcd_to_octeon(hcd); struct device *dev = hcd->self.controller; - int submit_handle = -1; - int pipe_handle; + struct cvmx_usb_transaction *transaction = NULL; + struct cvmx_usb_pipe *pipe; unsigned long flags; struct cvmx_usb_iso_packet *iso_packet; struct usb_host_endpoint *ep = urb->ep; @@ -276,26 +3076,24 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd, dev = dev->parent; } } - pipe_handle = cvmx_usb_open_pipe(&priv->usb, - 0, - usb_pipedevice(urb->pipe), - usb_pipeendpoint(urb->pipe), - speed, - le16_to_cpu(ep->desc.wMaxPacketSize) & 0x7ff, - transfer_type, - usb_pipein(urb->pipe) ? CVMX_USB_DIRECTION_IN : CVMX_USB_DIRECTION_OUT, - urb->interval, - (le16_to_cpu(ep->desc.wMaxPacketSize) >> 11) & 0x3, - split_device, - split_port); - if (pipe_handle < 0) { + pipe = cvmx_usb_open_pipe(&priv->usb, usb_pipedevice(urb->pipe), + usb_pipeendpoint(urb->pipe), speed, + le16_to_cpu(ep->desc.wMaxPacketSize) & 0x7ff, + transfer_type, + usb_pipein(urb->pipe) ? + CVMX_USB_DIRECTION_IN : + CVMX_USB_DIRECTION_OUT, + urb->interval, + (le16_to_cpu(ep->desc.wMaxPacketSize) >> 11) & 0x3, + split_device, split_port); + if (!pipe) { spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(dev, "Failed to create pipe\n"); return -ENOMEM; } - ep->hcpriv = (void *)(0x10000L + pipe_handle); + ep->hcpriv = pipe; } else { - pipe_handle = 0xffff & (long)ep->hcpriv; + pipe = ep->hcpriv; } switch (usb_pipetype(urb->pipe)) { @@ -323,20 +3121,13 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd, * this saves us a bunch of logic. */ urb->setup_packet = (char *)iso_packet; - submit_handle = cvmx_usb_submit_isochronous(&priv->usb, pipe_handle, - urb->start_frame, - 0 /* flags */ , - urb->number_of_packets, - iso_packet, - urb->transfer_dma, - urb->transfer_buffer_length, - octeon_usb_urb_complete_callback, - urb); + transaction = cvmx_usb_submit_isochronous(&priv->usb, + pipe, urb); /* * If submit failed we need to free our private packet * list. */ - if (submit_handle < 0) { + if (!transaction) { urb->setup_packet = NULL; kfree(iso_packet); } @@ -345,59 +3136,41 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd, case PIPE_INTERRUPT: dev_dbg(dev, "Submit interrupt to %d.%d\n", usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe)); - submit_handle = cvmx_usb_submit_interrupt(&priv->usb, pipe_handle, - urb->transfer_dma, - urb->transfer_buffer_length, - octeon_usb_urb_complete_callback, - urb); + transaction = cvmx_usb_submit_interrupt(&priv->usb, pipe, urb); break; case PIPE_CONTROL: dev_dbg(dev, "Submit control to %d.%d\n", usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe)); - submit_handle = cvmx_usb_submit_control(&priv->usb, pipe_handle, - urb->setup_dma, - urb->transfer_dma, - urb->transfer_buffer_length, - octeon_usb_urb_complete_callback, - urb); + transaction = cvmx_usb_submit_control(&priv->usb, pipe, urb); break; case PIPE_BULK: dev_dbg(dev, "Submit bulk to %d.%d\n", usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe)); - submit_handle = cvmx_usb_submit_bulk(&priv->usb, pipe_handle, - urb->transfer_dma, - urb->transfer_buffer_length, - octeon_usb_urb_complete_callback, - urb); + transaction = cvmx_usb_submit_bulk(&priv->usb, pipe, urb); break; } - if (submit_handle < 0) { + if (!transaction) { spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(dev, "Failed to submit\n"); return -ENOMEM; } - urb->hcpriv = (void *)(long)(((submit_handle & 0xffff) << 16) | pipe_handle); + urb->hcpriv = transaction; spin_unlock_irqrestore(&priv->lock, flags); return 0; } static void octeon_usb_urb_dequeue_work(unsigned long arg) { + struct urb *urb; + struct urb *next; unsigned long flags; struct octeon_hcd *priv = (struct octeon_hcd *)arg; spin_lock_irqsave(&priv->lock, flags); - while (!list_empty(&priv->dequeue_list)) { - int pipe_handle; - int submit_handle; - struct urb *urb = container_of(priv->dequeue_list.next, struct urb, urb_list); - list_del(&urb->urb_list); - /* not enqueued on dequeue_list */ - INIT_LIST_HEAD(&urb->urb_list); - pipe_handle = 0xffff & (long)urb->hcpriv; - submit_handle = ((long)urb->hcpriv) >> 16; - cvmx_usb_cancel(&priv->usb, pipe_handle, submit_handle); + list_for_each_entry_safe(urb, next, &priv->dequeue_list, urb_list) { + list_del_init(&urb->urb_list); + cvmx_usb_cancel(&priv->usb, urb->ep->hcpriv, urb->hcpriv); } spin_unlock_irqrestore(&priv->lock, flags); @@ -429,12 +3202,12 @@ static void octeon_usb_endpoint_disable(struct usb_hcd *hcd, struct usb_host_end if (ep->hcpriv) { struct octeon_hcd *priv = hcd_to_octeon(hcd); - int pipe_handle = 0xffff & (long)ep->hcpriv; + struct cvmx_usb_pipe *pipe = ep->hcpriv; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - cvmx_usb_cancel_all(&priv->usb, pipe_handle); - if (cvmx_usb_close_pipe(&priv->usb, pipe_handle)) - dev_dbg(dev, "Closing pipe %d failed\n", pipe_handle); + cvmx_usb_cancel_all(&priv->usb, pipe); + if (cvmx_usb_close_pipe(&priv->usb, pipe)) + dev_dbg(dev, "Closing pipe %p failed\n", pipe); spin_unlock_irqrestore(&priv->lock, flags); ep->hcpriv = NULL; } @@ -506,7 +3279,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, dev_dbg(dev, " C_CONNECTION\n"); /* Clears drivers internal connect status change flag */ spin_lock_irqsave(&priv->lock, flags); - cvmx_usb_set_status(&priv->usb, cvmx_usb_get_status(&priv->usb)); + priv->usb.port_status = cvmx_usb_get_status(&priv->usb); spin_unlock_irqrestore(&priv->lock, flags); break; case USB_PORT_FEAT_C_RESET: @@ -515,7 +3288,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, * Clears the driver's internal Port Reset Change flag. */ spin_lock_irqsave(&priv->lock, flags); - cvmx_usb_set_status(&priv->usb, cvmx_usb_get_status(&priv->usb)); + priv->usb.port_status = cvmx_usb_get_status(&priv->usb); spin_unlock_irqrestore(&priv->lock, flags); break; case USB_PORT_FEAT_C_ENABLE: @@ -525,7 +3298,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, * Change flag. */ spin_lock_irqsave(&priv->lock, flags); - cvmx_usb_set_status(&priv->usb, cvmx_usb_get_status(&priv->usb)); + priv->usb.port_status = cvmx_usb_get_status(&priv->usb); spin_unlock_irqrestore(&priv->lock, flags); break; case USB_PORT_FEAT_C_SUSPEND: @@ -540,7 +3313,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, dev_dbg(dev, " C_OVER_CURRENT\n"); /* Clears the driver's overcurrent Change flag */ spin_lock_irqsave(&priv->lock, flags); - cvmx_usb_set_status(&priv->usb, cvmx_usb_get_status(&priv->usb)); + priv->usb.port_status = cvmx_usb_get_status(&priv->usb); spin_unlock_irqrestore(&priv->lock, flags); break; default: @@ -705,7 +3478,7 @@ static int octeon_usb_driver_probe(struct device *dev) tasklet_init(&priv->dequeue_tasklet, octeon_usb_urb_dequeue_work, (unsigned long)priv); INIT_LIST_HEAD(&priv->dequeue_list); - status = cvmx_usb_initialize(&priv->usb, usb_num, CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO); + status = cvmx_usb_initialize(&priv->usb, usb_num); if (status) { dev_dbg(dev, "USB initialization failed with %d\n", status); kfree(hcd); diff --git a/drivers/staging/octeon-usb/cvmx-usbcx-defs.h b/drivers/staging/octeon-usb/octeon-hcd.h index d349d77bc359..42fe4fec7d5d 100644 --- a/drivers/staging/octeon-usb/cvmx-usbcx-defs.h +++ b/drivers/staging/octeon-usb/octeon-hcd.h @@ -1,7 +1,14 @@ -/***********************license start*************** - * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights - * reserved. +/* + * Octeon HCD hardware register definitions. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * + * Some parts of the code were originally released under BSD license: + * + * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights + * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -14,17 +21,17 @@ * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - + * * * Neither the name of Cavium Networks nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. - + * * This Software, including technical data, may be subject to U.S. export * control laws, including the U.S. Export Administration Act and its associated - * regulations, and may be subject to export or import regulations in other + * regulations, and may be subject to export or import regulations in other * countries. - + * * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO @@ -33,20 +40,12 @@ * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR - * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR + * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. - ***********************license end**************************************/ - - -/** - * cvmx-usbcx-defs.h - * - * Configuration and status register (CSR) type definitions for - * Octeon usbcx. - * */ -#ifndef __CVMX_USBCX_TYPEDEFS_H__ -#define __CVMX_USBCX_TYPEDEFS_H__ + +#ifndef __OCTEON_HCD_H__ +#define __OCTEON_HCD_H__ #define CVMX_USBCXBASE 0x00016F0010000000ull #define CVMX_USBCXREG1(reg, bid) \ @@ -81,6 +80,19 @@ #define CVMX_USBCX_HPTXFSIZ(bid) CVMX_USBCXREG1(0x100, bid) #define CVMX_USBCX_HPTXSTS(bid) CVMX_USBCXREG1(0x410, bid) +#define CVMX_USBNXBID1(bid) (((bid) & 1) * 0x10000000ull) +#define CVMX_USBNXBID2(bid) (((bid) & 1) * 0x100000000000ull) + +#define CVMX_USBNXREG1(reg, bid) \ + (CVMX_ADD_IO_SEG(0x0001180068000000ull | reg) + CVMX_USBNXBID1(bid)) +#define CVMX_USBNXREG2(reg, bid) \ + (CVMX_ADD_IO_SEG(0x00016F0000000000ull | reg) + CVMX_USBNXBID2(bid)) + +#define CVMX_USBNX_CLK_CTL(bid) CVMX_USBNXREG1(0x10, bid) +#define CVMX_USBNX_DMA0_INB_CHN0(bid) CVMX_USBNXREG2(0x818, bid) +#define CVMX_USBNX_DMA0_OUTB_CHN0(bid) CVMX_USBNXREG2(0x858, bid) +#define CVMX_USBNX_USBP_CTL_STATUS(bid) CVMX_USBNXREG1(0x18, bid) + /** * cvmx_usbc#_gahbcfg * @@ -1525,4 +1537,283 @@ union cvmx_usbcx_hptxsts { } s; }; -#endif +/** + * cvmx_usbn#_clk_ctl + * + * USBN_CLK_CTL = USBN's Clock Control + * + * This register is used to control the frequency of the hclk and the + * hreset and phy_rst signals. + */ +union cvmx_usbnx_clk_ctl { + uint64_t u64; + /** + * struct cvmx_usbnx_clk_ctl_s + * @divide2: The 'hclk' used by the USB subsystem is derived + * from the eclk. + * Also see the field DIVIDE. DIVIDE2<1> must currently + * be zero because it is not implemented, so the maximum + * ratio of eclk/hclk is currently 16. + * The actual divide number for hclk is: + * (DIVIDE2 + 1) * (DIVIDE + 1) + * @hclk_rst: When this field is '0' the HCLK-DIVIDER used to + * generate the hclk in the USB Subsystem is held + * in reset. This bit must be set to '0' before + * changing the value os DIVIDE in this register. + * The reset to the HCLK_DIVIDERis also asserted + * when core reset is asserted. + * @p_x_on: Force USB-PHY on during suspend. + * '1' USB-PHY XO block is powered-down during + * suspend. + * '0' USB-PHY XO block is powered-up during + * suspend. + * The value of this field must be set while POR is + * active. + * @p_rtype: PHY reference clock type + * On CN50XX/CN52XX/CN56XX the values are: + * '0' The USB-PHY uses a 12MHz crystal as a clock source + * at the USB_XO and USB_XI pins. + * '1' Reserved. + * '2' The USB_PHY uses 12/24/48MHz 2.5V board clock at the + * USB_XO pin. USB_XI should be tied to ground in this + * case. + * '3' Reserved. + * On CN3xxx bits 14 and 15 are p_xenbn and p_rclk and values are: + * '0' Reserved. + * '1' Reserved. + * '2' The PHY PLL uses the XO block output as a reference. + * The XO block uses an external clock supplied on the + * XO pin. USB_XI should be tied to ground for this + * usage. + * '3' The XO block uses the clock from a crystal. + * @p_com_on: '0' Force USB-PHY XO Bias, Bandgap and PLL to + * remain powered in Suspend Mode. + * '1' The USB-PHY XO Bias, Bandgap and PLL are + * powered down in suspend mode. + * The value of this field must be set while POR is + * active. + * @p_c_sel: Phy clock speed select. + * Selects the reference clock / crystal frequency. + * '11': Reserved + * '10': 48 MHz (reserved when a crystal is used) + * '01': 24 MHz (reserved when a crystal is used) + * '00': 12 MHz + * The value of this field must be set while POR is + * active. + * NOTE: if a crystal is used as a reference clock, + * this field must be set to 12 MHz. + * @cdiv_byp: Used to enable the bypass input to the USB_CLK_DIV. + * @sd_mode: Scaledown mode for the USBC. Control timing events + * in the USBC, for normal operation this must be '0'. + * @s_bist: Starts bist on the hclk memories, during the '0' + * to '1' transition. + * @por: Power On Reset for the PHY. + * Resets all the PHYS registers and state machines. + * @enable: When '1' allows the generation of the hclk. When + * '0' the hclk will not be generated. SEE DIVIDE + * field of this register. + * @prst: When this field is '0' the reset associated with + * the phy_clk functionality in the USB Subsystem is + * help in reset. This bit should not be set to '1' + * until the time it takes 6 clocks (hclk or phy_clk, + * whichever is slower) has passed. Under normal + * operation once this bit is set to '1' it should not + * be set to '0'. + * @hrst: When this field is '0' the reset associated with + * the hclk functioanlity in the USB Subsystem is + * held in reset.This bit should not be set to '1' + * until 12ms after phy_clk is stable. Under normal + * operation, once this bit is set to '1' it should + * not be set to '0'. + * @divide: The frequency of 'hclk' used by the USB subsystem + * is the eclk frequency divided by the value of + * (DIVIDE2 + 1) * (DIVIDE + 1), also see the field + * DIVIDE2 of this register. + * The hclk frequency should be less than 125Mhz. + * After writing a value to this field the SW should + * read the field for the value written. + * The ENABLE field of this register should not be set + * until AFTER this field is set and then read. + */ + struct cvmx_usbnx_clk_ctl_s { + uint64_t reserved_20_63 : 44; + uint64_t divide2 : 2; + uint64_t hclk_rst : 1; + uint64_t p_x_on : 1; + uint64_t p_rtype : 2; + uint64_t p_com_on : 1; + uint64_t p_c_sel : 2; + uint64_t cdiv_byp : 1; + uint64_t sd_mode : 2; + uint64_t s_bist : 1; + uint64_t por : 1; + uint64_t enable : 1; + uint64_t prst : 1; + uint64_t hrst : 1; + uint64_t divide : 3; + } s; +}; + +/** + * cvmx_usbn#_usbp_ctl_status + * + * USBN_USBP_CTL_STATUS = USBP Control And Status Register + * + * Contains general control and status information for the USBN block. + */ +union cvmx_usbnx_usbp_ctl_status { + uint64_t u64; + /** + * struct cvmx_usbnx_usbp_ctl_status_s + * @txrisetune: HS Transmitter Rise/Fall Time Adjustment + * @txvreftune: HS DC Voltage Level Adjustment + * @txfslstune: FS/LS Source Impedence Adjustment + * @txhsxvtune: Transmitter High-Speed Crossover Adjustment + * @sqrxtune: Squelch Threshold Adjustment + * @compdistune: Disconnect Threshold Adjustment + * @otgtune: VBUS Valid Threshold Adjustment + * @otgdisable: OTG Block Disable + * @portreset: Per_Port Reset + * @drvvbus: Drive VBUS + * @lsbist: Low-Speed BIST Enable. + * @fsbist: Full-Speed BIST Enable. + * @hsbist: High-Speed BIST Enable. + * @bist_done: PHY Bist Done. + * Asserted at the end of the PHY BIST sequence. + * @bist_err: PHY Bist Error. + * Indicates an internal error was detected during + * the BIST sequence. + * @tdata_out: PHY Test Data Out. + * Presents either internaly generated signals or + * test register contents, based upon the value of + * test_data_out_sel. + * @siddq: Drives the USBP (USB-PHY) SIDDQ input. + * Normally should be set to zero. + * When customers have no intent to use USB PHY + * interface, they should: + * - still provide 3.3V to USB_VDD33, and + * - tie USB_REXT to 3.3V supply, and + * - set USBN*_USBP_CTL_STATUS[SIDDQ]=1 + * @txpreemphasistune: HS Transmitter Pre-Emphasis Enable + * @dma_bmode: When set to 1 the L2C DMA address will be updated + * with byte-counts between packets. When set to 0 + * the L2C DMA address is incremented to the next + * 4-byte aligned address after adding byte-count. + * @usbc_end: Bigendian input to the USB Core. This should be + * set to '0' for operation. + * @usbp_bist: PHY, This is cleared '0' to run BIST on the USBP. + * @tclk: PHY Test Clock, used to load TDATA_IN to the USBP. + * @dp_pulld: PHY DP_PULLDOWN input to the USB-PHY. + * This signal enables the pull-down resistance on + * the D+ line. '1' pull down-resistance is connected + * to D+/ '0' pull down resistance is not connected + * to D+. When an A/B device is acting as a host + * (downstream-facing port), dp_pulldown and + * dm_pulldown are enabled. This must not toggle + * during normal opeartion. + * @dm_pulld: PHY DM_PULLDOWN input to the USB-PHY. + * This signal enables the pull-down resistance on + * the D- line. '1' pull down-resistance is connected + * to D-. '0' pull down resistance is not connected + * to D-. When an A/B device is acting as a host + * (downstream-facing port), dp_pulldown and + * dm_pulldown are enabled. This must not toggle + * during normal opeartion. + * @hst_mode: When '0' the USB is acting as HOST, when '1' + * USB is acting as device. This field needs to be + * set while the USB is in reset. + * @tuning: Transmitter Tuning for High-Speed Operation. + * Tunes the current supply and rise/fall output + * times for high-speed operation. + * [20:19] == 11: Current supply increased + * approximately 9% + * [20:19] == 10: Current supply increased + * approximately 4.5% + * [20:19] == 01: Design default. + * [20:19] == 00: Current supply decreased + * approximately 4.5% + * [22:21] == 11: Rise and fall times are increased. + * [22:21] == 10: Design default. + * [22:21] == 01: Rise and fall times are decreased. + * [22:21] == 00: Rise and fall times are decreased + * further as compared to the 01 setting. + * @tx_bs_enh: Transmit Bit Stuffing on [15:8]. + * Enables or disables bit stuffing on data[15:8] + * when bit-stuffing is enabled. + * @tx_bs_en: Transmit Bit Stuffing on [7:0]. + * Enables or disables bit stuffing on data[7:0] + * when bit-stuffing is enabled. + * @loop_enb: PHY Loopback Test Enable. + * '1': During data transmission the receive is + * enabled. + * '0': During data transmission the receive is + * disabled. + * Must be '0' for normal operation. + * @vtest_enb: Analog Test Pin Enable. + * '1' The PHY's analog_test pin is enabled for the + * input and output of applicable analog test signals. + * '0' THe analog_test pin is disabled. + * @bist_enb: Built-In Self Test Enable. + * Used to activate BIST in the PHY. + * @tdata_sel: Test Data Out Select. + * '1' test_data_out[3:0] (PHY) register contents + * are output. '0' internaly generated signals are + * output. + * @taddr_in: Mode Address for Test Interface. + * Specifies the register address for writing to or + * reading from the PHY test interface register. + * @tdata_in: Internal Testing Register Input Data and Select + * This is a test bus. Data is present on [3:0], + * and its corresponding select (enable) is present + * on bits [7:4]. + * @ate_reset: Reset input from automatic test equipment. + * This is a test signal. When the USB Core is + * powered up (not in Susned Mode), an automatic + * tester can use this to disable phy_clock and + * free_clk, then re-eanable them with an aligned + * phase. + * '1': The phy_clk and free_clk outputs are + * disabled. "0": The phy_clock and free_clk outputs + * are available within a specific period after the + * de-assertion. + */ + struct cvmx_usbnx_usbp_ctl_status_s { + uint64_t txrisetune : 1; + uint64_t txvreftune : 4; + uint64_t txfslstune : 4; + uint64_t txhsxvtune : 2; + uint64_t sqrxtune : 3; + uint64_t compdistune : 3; + uint64_t otgtune : 3; + uint64_t otgdisable : 1; + uint64_t portreset : 1; + uint64_t drvvbus : 1; + uint64_t lsbist : 1; + uint64_t fsbist : 1; + uint64_t hsbist : 1; + uint64_t bist_done : 1; + uint64_t bist_err : 1; + uint64_t tdata_out : 4; + uint64_t siddq : 1; + uint64_t txpreemphasistune : 1; + uint64_t dma_bmode : 1; + uint64_t usbc_end : 1; + uint64_t usbp_bist : 1; + uint64_t tclk : 1; + uint64_t dp_pulld : 1; + uint64_t dm_pulld : 1; + uint64_t hst_mode : 1; + uint64_t tuning : 4; + uint64_t tx_bs_enh : 1; + uint64_t tx_bs_en : 1; + uint64_t loop_enb : 1; + uint64_t vtest_enb : 1; + uint64_t bist_enb : 1; + uint64_t tdata_sel : 1; + uint64_t taddr_in : 4; + uint64_t tdata_in : 8; + uint64_t ate_reset : 1; + } s; +}; + +#endif /* __OCTEON_HCD_H__ */ diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index e14a1bb04361..0315f60497b7 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -72,7 +72,7 @@ struct cvm_oct_core_state { int baseline_cores; /* * The number of additional cores that could be processing - * input packtes. + * input packets. */ atomic_t available_cores; cpumask_t cpu_state; @@ -80,6 +80,8 @@ struct cvm_oct_core_state { static struct cvm_oct_core_state core_state __cacheline_aligned_in_smp; +static int cvm_irq_cpu; + static void cvm_oct_enable_napi(void *_) { int cpu = smp_processor_id(); @@ -112,11 +114,7 @@ static void cvm_oct_no_more_work(void) { int cpu = smp_processor_id(); - /* - * CPU zero is special. It always has the irq enabled when - * waiting for incoming packets. - */ - if (cpu == 0) { + if (cpu == cvm_irq_cpu) { enable_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group); return; } @@ -135,6 +133,7 @@ static irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id) { /* Disable the IRQ and start napi_poll. */ disable_irq_nosync(OCTEON_IRQ_WORKQ0 + pow_receive_group); + cvm_irq_cpu = smp_processor_id(); cvm_oct_enable_napi(NULL); return IRQ_HANDLED; @@ -514,7 +513,7 @@ void cvm_oct_rx_initialize(void) if (NULL == dev_for_napi) panic("No net_devices were allocated."); - if (max_rx_cpus > 1 && max_rx_cpus < num_online_cpus()) + if (max_rx_cpus >= 1 && max_rx_cpus < num_online_cpus()) atomic_set(&core_state.available_cores, max_rx_cpus); else atomic_set(&core_state.available_cores, num_online_cpus()); @@ -526,7 +525,7 @@ void cvm_oct_rx_initialize(void) cvm_oct_napi_poll, rx_napi_weight); napi_enable(&cvm_oct_napi[i].napi); } - /* Register an IRQ hander for to receive POW interrupts */ + /* Register an IRQ handler to receive POW interrupts */ i = request_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group, cvm_oct_do_interrupt, 0, "Ethernet", cvm_oct_device); diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c index af8d62818f13..5108bc0bb573 100644 --- a/drivers/staging/octeon/ethernet-spi.c +++ b/drivers/staging/octeon/ethernet-spi.c @@ -64,31 +64,23 @@ static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id) if (spx_int_reg.s.spf) pr_err("SPI1: SRX Spi4 interface down\n"); if (spx_int_reg.s.calerr) - pr_err("SPI1: SRX Spi4 Calendar table " - "parity error\n"); + pr_err("SPI1: SRX Spi4 Calendar table parity error\n"); if (spx_int_reg.s.syncerr) - pr_err("SPI1: SRX Consecutive Spi4 DIP4 " - "errors have exceeded " - "SPX_ERR_CTL[ERRCNT]\n"); + pr_err("SPI1: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n"); if (spx_int_reg.s.diperr) pr_err("SPI1: SRX Spi4 DIP4 error\n"); if (spx_int_reg.s.tpaovr) - pr_err("SPI1: SRX Selected port has hit " - "TPA overflow\n"); + pr_err("SPI1: SRX Selected port has hit TPA overflow\n"); if (spx_int_reg.s.rsverr) - pr_err("SPI1: SRX Spi4 reserved control " - "word detected\n"); + pr_err("SPI1: SRX Spi4 reserved control word detected\n"); if (spx_int_reg.s.drwnng) - pr_err("SPI1: SRX Spi4 receive FIFO " - "drowning/overflow\n"); + pr_err("SPI1: SRX Spi4 receive FIFO drowning/overflow\n"); if (spx_int_reg.s.clserr) - pr_err("SPI1: SRX Spi4 packet closed on " - "non-16B alignment without EOP\n"); + pr_err("SPI1: SRX Spi4 packet closed on non-16B alignment without EOP\n"); if (spx_int_reg.s.spiovr) pr_err("SPI1: SRX Spi4 async FIFO overflow\n"); if (spx_int_reg.s.abnorm) - pr_err("SPI1: SRX Abnormal packet " - "termination (ERR bit)\n"); + pr_err("SPI1: SRX Abnormal packet termination (ERR bit)\n"); if (spx_int_reg.s.prtnxa) pr_err("SPI1: SRX Port out of range\n"); } @@ -99,31 +91,23 @@ static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id) stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1)); if (stx_int_reg.s.syncerr) - pr_err("SPI1: STX Interface encountered a " - "fatal error\n"); + pr_err("SPI1: STX Interface encountered a fatal error\n"); if (stx_int_reg.s.frmerr) - pr_err("SPI1: STX FRMCNT has exceeded " - "STX_DIP_CNT[MAXFRM]\n"); + pr_err("SPI1: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n"); if (stx_int_reg.s.unxfrm) - pr_err("SPI1: STX Unexpected framing " - "sequence\n"); + pr_err("SPI1: STX Unexpected framing sequence\n"); if (stx_int_reg.s.nosync) - pr_err("SPI1: STX ERRCNT has exceeded " - "STX_DIP_CNT[MAXDIP]\n"); + pr_err("SPI1: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n"); if (stx_int_reg.s.diperr) - pr_err("SPI1: STX DIP2 error on the Spi4 " - "Status channel\n"); + pr_err("SPI1: STX DIP2 error on the Spi4 Status channel\n"); if (stx_int_reg.s.datovr) pr_err("SPI1: STX Spi4 FIFO overflow error\n"); if (stx_int_reg.s.ovrbst) - pr_err("SPI1: STX Transmit packet burst " - "too big\n"); + pr_err("SPI1: STX Transmit packet burst too big\n"); if (stx_int_reg.s.calpar1) - pr_err("SPI1: STX Calendar Table Parity " - "Error Bank1\n"); + pr_err("SPI1: STX Calendar Table Parity Error Bank1\n"); if (stx_int_reg.s.calpar0) - pr_err("SPI1: STX Calendar Table Parity " - "Error Bank0\n"); + pr_err("SPI1: STX Calendar Table Parity Error Bank0\n"); } cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0); @@ -144,31 +128,23 @@ static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id) if (spx_int_reg.s.spf) pr_err("SPI0: SRX Spi4 interface down\n"); if (spx_int_reg.s.calerr) - pr_err("SPI0: SRX Spi4 Calendar table " - "parity error\n"); + pr_err("SPI0: SRX Spi4 Calendar table parity error\n"); if (spx_int_reg.s.syncerr) - pr_err("SPI0: SRX Consecutive Spi4 DIP4 " - "errors have exceeded " - "SPX_ERR_CTL[ERRCNT]\n"); + pr_err("SPI0: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n"); if (spx_int_reg.s.diperr) pr_err("SPI0: SRX Spi4 DIP4 error\n"); if (spx_int_reg.s.tpaovr) - pr_err("SPI0: SRX Selected port has hit " - "TPA overflow\n"); + pr_err("SPI0: SRX Selected port has hit TPA overflow\n"); if (spx_int_reg.s.rsverr) - pr_err("SPI0: SRX Spi4 reserved control " - "word detected\n"); + pr_err("SPI0: SRX Spi4 reserved control word detected\n"); if (spx_int_reg.s.drwnng) - pr_err("SPI0: SRX Spi4 receive FIFO " - "drowning/overflow\n"); + pr_err("SPI0: SRX Spi4 receive FIFO drowning/overflow\n"); if (spx_int_reg.s.clserr) - pr_err("SPI0: SRX Spi4 packet closed on " - "non-16B alignment without EOP\n"); + pr_err("SPI0: SRX Spi4 packet closed on non-16B alignment without EOP\n"); if (spx_int_reg.s.spiovr) pr_err("SPI0: SRX Spi4 async FIFO overflow\n"); if (spx_int_reg.s.abnorm) - pr_err("SPI0: SRX Abnormal packet " - "termination (ERR bit)\n"); + pr_err("SPI0: SRX Abnormal packet termination (ERR bit)\n"); if (spx_int_reg.s.prtnxa) pr_err("SPI0: SRX Port out of range\n"); } @@ -179,31 +155,23 @@ static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id) stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0)); if (stx_int_reg.s.syncerr) - pr_err("SPI0: STX Interface encountered a " - "fatal error\n"); + pr_err("SPI0: STX Interface encountered a fatal error\n"); if (stx_int_reg.s.frmerr) - pr_err("SPI0: STX FRMCNT has exceeded " - "STX_DIP_CNT[MAXFRM]\n"); + pr_err("SPI0: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n"); if (stx_int_reg.s.unxfrm) - pr_err("SPI0: STX Unexpected framing " - "sequence\n"); + pr_err("SPI0: STX Unexpected framing sequence\n"); if (stx_int_reg.s.nosync) - pr_err("SPI0: STX ERRCNT has exceeded " - "STX_DIP_CNT[MAXDIP]\n"); + pr_err("SPI0: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n"); if (stx_int_reg.s.diperr) - pr_err("SPI0: STX DIP2 error on the Spi4 " - "Status channel\n"); + pr_err("SPI0: STX DIP2 error on the Spi4 Status channel\n"); if (stx_int_reg.s.datovr) pr_err("SPI0: STX Spi4 FIFO overflow error\n"); if (stx_int_reg.s.ovrbst) - pr_err("SPI0: STX Transmit packet burst " - "too big\n"); + pr_err("SPI0: STX Transmit packet burst too big\n"); if (stx_int_reg.s.calpar1) - pr_err("SPI0: STX Calendar Table Parity " - "Error Bank1\n"); + pr_err("SPI0: STX Calendar Table Parity Error Bank1\n"); if (stx_int_reg.s.calpar0) - pr_err("SPI0: STX Calendar Table Parity " - "Error Bank0\n"); + pr_err("SPI0: STX Calendar Table Parity Error Bank0\n"); } cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0); diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 5631dd9f8201..9b4d0b546b89 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -78,10 +78,12 @@ static DECLARE_TASKLET(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup, 0); static inline int32_t cvm_oct_adjust_skb_to_free(int32_t skb_to_free, int fau) { int32_t undo; - undo = skb_to_free > 0 ? MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE; + undo = skb_to_free > 0 ? MAX_SKB_TO_FREE : skb_to_free + + MAX_SKB_TO_FREE; if (undo > 0) cvmx_fau_atomic_add32(fau, -undo); - skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ? MAX_SKB_TO_FREE : -skb_to_free; + skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ? MAX_SKB_TO_FREE : + -skb_to_free; return skb_to_free; } @@ -108,8 +110,10 @@ void cvm_oct_free_tx_skbs(struct net_device *dev) for (qos = 0; qos < queues_per_port; qos++) { if (skb_queue_len(&priv->tx_free_list[qos]) == 0) continue; - skb_to_free = cvmx_fau_fetch_and_add32(priv->fau+qos*4, MAX_SKB_TO_FREE); - skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau+qos*4); + skb_to_free = cvmx_fau_fetch_and_add32(priv->fau+qos*4, + MAX_SKB_TO_FREE); + skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, + priv->fau+qos*4); total_freed += skb_to_free; @@ -117,12 +121,14 @@ void cvm_oct_free_tx_skbs(struct net_device *dev) struct sk_buff *to_free_list = NULL; spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); while (skb_to_free > 0) { - struct sk_buff *t = __skb_dequeue(&priv->tx_free_list[qos]); + struct sk_buff *t; + t = __skb_dequeue(&priv->tx_free_list[qos]); t->next = to_free_list; to_free_list = t; skb_to_free--; } - spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags); + spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, + flags); /* Do the actual freeing outside of the lock. */ while (to_free_list) { struct sk_buff *t = to_free_list; @@ -211,15 +217,23 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(__skb_linearize(skb))) { queue_type = QUEUE_DROP; if (USE_ASYNC_IOBDMA) { - /* Get the number of skbuffs in use by the hardware */ + /* + * Get the number of skbuffs in use + * by the hardware + */ CVMX_SYNCIOBDMA; - skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH); + skb_to_free = + cvmx_scratch_read64(CVMX_SCR_SCRATCH); } else { - /* Get the number of skbuffs in use by the hardware */ - skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4, - MAX_SKB_TO_FREE); + /* + * Get the number of skbuffs in use + * by the hardware + */ + skb_to_free = cvmx_fau_fetch_and_add32( + priv->fau + qos * 4, MAX_SKB_TO_FREE); } - skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau + qos * 4); + skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, + priv->fau + qos * 4); spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); goto skip_xmit; } @@ -276,7 +290,9 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) CVM_OCT_SKB_CB(skb)[0] = hw_buffer.u64; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *fs = skb_shinfo(skb)->frags + i; - hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page.p) + fs->page_offset)); + hw_buffer.s.addr = XKPHYS_TO_PHYS( + (u64)(page_address(fs->page.p) + + fs->page_offset)); hw_buffer.s.size = fs->size; CVM_OCT_SKB_CB(skb)[i + 1] = hw_buffer.u64; } @@ -358,7 +374,9 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) */ pko_command.s.dontfree = 0; - hw_buffer.s.back = ((unsigned long)skb->data >> 7) - ((unsigned long)fpa_head >> 7); + hw_buffer.s.back = ((unsigned long)skb->data >> 7) - + ((unsigned long)fpa_head >> 7); + *(struct sk_buff **)(fpa_head - sizeof(void *)) = skb; /* @@ -422,17 +440,22 @@ dont_put_skbuff_in_hw: queue_type = QUEUE_HW; } if (USE_ASYNC_IOBDMA) - cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH, FAU_TOTAL_TX_TO_CLEAN, 1); + cvmx_fau_async_fetch_and_add32( + CVMX_SCR_SCRATCH, FAU_TOTAL_TX_TO_CLEAN, 1); spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); /* Drop this packet if we have too many already queued to the HW */ - if (unlikely(skb_queue_len(&priv->tx_free_list[qos]) >= MAX_OUT_QUEUE_DEPTH)) { + if (unlikely(skb_queue_len(&priv->tx_free_list[qos]) >= + MAX_OUT_QUEUE_DEPTH)) { + if (dev->tx_queue_len != 0) { /* Drop the lock when notifying the core. */ - spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags); + spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, + flags); netif_stop_queue(dev); - spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); + spin_lock_irqsave(&priv->tx_free_list[qos].lock, + flags); } else { /* If not using normal queueing. */ queue_type = QUEUE_DROP; @@ -448,7 +471,8 @@ dont_put_skbuff_in_hw: priv->queue + qos, pko_command, hw_buffer, CVMX_PKO_LOCK_NONE))) { - printk_ratelimited("%s: Failed to send the packet\n", dev->name); + printk_ratelimited("%s: Failed to send the packet\n", + dev->name); queue_type = QUEUE_DROP; } skip_xmit: @@ -493,7 +517,8 @@ skip_xmit: cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2); } else { - total_to_clean = cvmx_fau_fetch_and_add32(FAU_TOTAL_TX_TO_CLEAN, 1); + total_to_clean = cvmx_fau_fetch_and_add32( + FAU_TOTAL_TX_TO_CLEAN, 1); } if (total_to_clean & 0x3ff) { @@ -527,8 +552,8 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) /* Get a work queue entry */ cvmx_wqe_t *work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL); if (unlikely(work == NULL)) { - printk_ratelimited("%s: Failed to allocate a work " - "queue entry\n", dev->name); + printk_ratelimited("%s: Failed to allocate a work queue entry\n", + dev->name); priv->stats.tx_dropped++; dev_kfree_skb(skb); return 0; @@ -709,7 +734,7 @@ void cvm_oct_tx_initialize(void) /* Disable the interrupt. */ cvmx_write_csr(CVMX_CIU_TIMX(1), 0); - /* Register an IRQ hander for to receive CIU_TIMX(1) interrupts */ + /* Register an IRQ handler to receive CIU_TIMX(1) interrupts */ i = request_irq(OCTEON_IRQ_TIMER1, cvm_oct_tx_cleanup_watchdog, 0, "Ethernet", cvm_oct_device); diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index c3a90e7012af..8aba66e4a3e4 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -163,11 +163,13 @@ static void cvm_oct_periodic_worker(struct work_struct *work) if (priv->poll) priv->poll(cvm_oct_device[priv->port]); - cvm_oct_device[priv->port]->netdev_ops->ndo_get_stats(cvm_oct_device[priv->port]); + cvm_oct_device[priv->port]->netdev_ops->ndo_get_stats( + cvm_oct_device[priv->port]); if (!atomic_read(&cvm_oct_poll_queue_stopping)) - queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ); - } + queue_delayed_work(cvm_oct_poll_queue, + &priv->port_periodic_work, HZ); +} static void cvm_oct_configure_common_hw(void) { @@ -584,8 +586,8 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = { extern void octeon_mdiobus_force_mod_depencency(void); -static struct device_node *cvm_oct_of_get_child(const struct device_node *parent, - int reg_val) +static struct device_node *cvm_oct_of_get_child( + const struct device_node *parent, int reg_val) { struct device_node *node = NULL; int size; @@ -603,7 +605,7 @@ static struct device_node *cvm_oct_of_get_child(const struct device_node *parent } static struct device_node *cvm_oct_node_for_port(struct device_node *pip, - int interface, int port) + int interface, int port) { struct device_node *ni, *np; @@ -713,7 +715,8 @@ static int cvm_oct_probe(struct platform_device *pdev) int port; int port_index; - for (port_index = 0, port = cvmx_helper_get_ipd_port(interface, 0); + for (port_index = 0, + port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port_index++, port++) { struct octeon_ethernet *priv; @@ -726,7 +729,8 @@ static int cvm_oct_probe(struct platform_device *pdev) /* Initialize the device private structure. */ priv = netdev_priv(dev); - priv->of_node = cvm_oct_node_for_port(pip, interface, port_index); + priv->of_node = cvm_oct_node_for_port(pip, interface, + port_index); INIT_DELAYED_WORK(&priv->port_periodic_work, cvm_oct_periodic_worker); @@ -793,7 +797,7 @@ static int cvm_oct_probe(struct platform_device *pdev) cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t); queue_delayed_work(cvm_oct_poll_queue, - &priv->port_periodic_work, HZ); + &priv->port_periodic_work, HZ); } } } diff --git a/drivers/staging/olpc_dcon/Kconfig b/drivers/staging/olpc_dcon/Kconfig index 2ff015d84509..d277f048789e 100644 --- a/drivers/staging/olpc_dcon/Kconfig +++ b/drivers/staging/olpc_dcon/Kconfig @@ -1,7 +1,8 @@ config FB_OLPC_DCON tristate "One Laptop Per Child Display CONtroller support" depends on OLPC && FB - select I2C + depends on I2C + depends on (GPIO_CS5535 || GPIO_CS5535=n) select BACKLIGHT_CLASS_DEVICE ---help--- In order to support very low power operation, the XO laptop uses a diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 198595e8d742..92b02891704d 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -383,7 +383,7 @@ static void dcon_set_source(struct dcon_priv *dcon, int arg) dcon->pending_src = arg; - if ((dcon->curr_src != arg) && !work_pending(&dcon->switch_source)) + if (dcon->curr_src != arg) schedule_work(&dcon->switch_source); } diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c index 4247d60c9186..9f6ebdb23740 100644 --- a/drivers/staging/quickstart/quickstart.c +++ b/drivers/staging/quickstart/quickstart.c @@ -390,10 +390,6 @@ static int __init quickstart_init(void) { int ret; - /* ACPI Check */ - if (acpi_disabled) - return -ENODEV; - /* ACPI driver register */ ret = acpi_bus_register_driver(&quickstart_acpi_driver); if (ret) diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 5947a6f8e16f..48ce9a66907c 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -1704,7 +1704,7 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority, u16 RtsDur = 0; u16 ThisFrameTime = 0; u16 TxDescDuration = 0; - u8 ownbit_flag = false; + bool ownbit_flag = false; switch (priority) { case MANAGE_PRIORITY: @@ -3268,7 +3268,6 @@ fail_free: pci_disable_device(pdev); DMESG("wlan driver load failed\n"); - pci_set_drvdata(pdev, NULL); return ret; } diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c index b8f2ba010a04..d5a5f2089710 100644 --- a/drivers/staging/rtl8187se/r8180_dm.c +++ b/drivers/staging/rtl8187se/r8180_dm.c @@ -10,10 +10,10 @@ bool CheckHighPower(struct net_device *dev) struct r8180_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee80211; - if(!priv->bRegHighPowerMechanism) + if (!priv->bRegHighPowerMechanism) return false; - if(ieee->state == IEEE80211_LINKED_SCANNING) + if (ieee->state == IEEE80211_LINKED_SCANNING) return false; return true; @@ -57,15 +57,15 @@ void DoTxHighPower(struct net_device *dev) /* Stevenl suggested that degrade 8dbm in high power sate. 2007-12-04 Isaiah */ priv->bToUpdateTxPwr = true; - u1bTmp= read_nic_byte(dev, CCK_TXAGC); + u1bTmp = read_nic_byte(dev, CCK_TXAGC); /* If it never enter High Power. */ if (CckTxPwrIdx == u1bTmp) { - u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0; /* 8dbm */ + u1bTmp = (u1bTmp > 16) ? (u1bTmp - 16) : 0; /* 8dbm */ write_nic_byte(dev, CCK_TXAGC, u1bTmp); - u1bTmp= read_nic_byte(dev, OFDM_TXAGC); - u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0; /* 8dbm */ + u1bTmp = read_nic_byte(dev, OFDM_TXAGC); + u1bTmp = (u1bTmp > 16) ? (u1bTmp - 16) : 0; /* 8dbm */ write_nic_byte(dev, OFDM_TXAGC, u1bTmp); } @@ -74,12 +74,12 @@ void DoTxHighPower(struct net_device *dev) if (priv->bToUpdateTxPwr) { priv->bToUpdateTxPwr = false; /* SD3 required. */ - u1bTmp= read_nic_byte(dev, CCK_TXAGC); + u1bTmp = read_nic_byte(dev, CCK_TXAGC); if (u1bTmp < CckTxPwrIdx) { write_nic_byte(dev, CCK_TXAGC, CckTxPwrIdx); } - u1bTmp= read_nic_byte(dev, OFDM_TXAGC); + u1bTmp = read_nic_byte(dev, OFDM_TXAGC); if (u1bTmp < OfdmTxPwrIdx) { write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx); } @@ -97,7 +97,7 @@ void DoTxHighPower(struct net_device *dev) void rtl8180_tx_pw_wq(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,tx_pw_wq); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, tx_pw_wq); struct net_device *dev = ieee->dev; DoTxHighPower(dev); @@ -149,11 +149,11 @@ void DIG_Zebra(struct net_device *dev) #if 1 /* lzm reserved 080826 */ AwakePeriodIn2Sec = (2000 - priv->DozePeriodInPast2Sec); - priv ->DozePeriodInPast2Sec = 0; + priv->DozePeriodInPast2Sec = 0; if (AwakePeriodIn2Sec) { - OfdmFA1 = (u16)((OfdmFA1 * AwakePeriodIn2Sec) / 2000) ; - OfdmFA2 = (u16)((OfdmFA2 * AwakePeriodIn2Sec) / 2000) ; + OfdmFA1 = (u16)((OfdmFA1 * AwakePeriodIn2Sec) / 2000); + OfdmFA2 = (u16)((OfdmFA2 * AwakePeriodIn2Sec) / 2000); } else { ; } @@ -210,7 +210,7 @@ void DynamicInitGain(struct net_device *dev) void rtl8180_hw_dig_wq(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_dig_wq); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_dig_wq); struct net_device *dev = ieee->dev; struct r8180_priv *priv = ieee80211_priv(dev); @@ -234,7 +234,7 @@ int IncludedInSupportedRates(struct r8180_priv *priv, u8 TxRate) rate_len = priv->ieee80211->current_network.rates_len; rate_ex_len = priv->ieee80211->current_network.rates_ex_len; - for (idx=0; idx < rate_len; idx++) { + for (idx = 0; idx < rate_len; idx++) { if ((priv->ieee80211->current_network.rates[idx] & RateMask) == NaiveTxRate) { Found = 1; goto found_rate; @@ -247,7 +247,7 @@ int IncludedInSupportedRates(struct r8180_priv *priv, u8 TxRate) } } return Found; - found_rate: +found_rate: return Found; } @@ -397,7 +397,7 @@ void TxPwrTracking87SE(struct net_device *dev) tmpu1Byte = read_nic_byte(dev, EN_LPF_CAL); CurrentThermal = (tmpu1Byte & 0xf0) >> 4; /*[ 7:4]: thermal meter indication. */ - CurrentThermal = (CurrentThermal > 0x0c) ? 0x0c:CurrentThermal;/* lzm add 080826 */ + CurrentThermal = (CurrentThermal > 0x0c) ? 0x0c : CurrentThermal;/* lzm add 080826 */ if (CurrentThermal != priv->ThermalMeter) { /* Update Tx Power level on each channel. */ @@ -513,7 +513,7 @@ void StaRateAdaptive87SE(struct net_device *dev) */ /* - * 11Mbps or 36Mbps + * 11Mbps or 36Mbps * Check more times in these rate(key rates). */ if (priv->CurrentOperaRate == 22 || priv->CurrentOperaRate == 72) @@ -542,7 +542,7 @@ void StaRateAdaptive87SE(struct net_device *dev) } } else if (CurrSignalStrength > -47 && (CurrRetryRate < 50)) { /* - * 2For High Power + * 2For High Power * * Return to highest data rate, if signal strength is good enough. * SignalStrength threshold(-50dbm) is for RTL8186. @@ -577,8 +577,7 @@ void StaRateAdaptive87SE(struct net_device *dev) if (bTryDown && (CurrSignalStrength < -75)) /* cable link */ priv->TryDownCountLowData += TryDownTh; - } - else if (priv->CurrentOperaRate == 96) { + } else if (priv->CurrentOperaRate == 96) { /* 2For 48Mbps */ /* Air Link */ if (((CurrRetryRate > 48) && (priv->LastRetryRate > 47))) { @@ -593,7 +592,7 @@ void StaRateAdaptive87SE(struct net_device *dev) bTryUp = true; } - if (bTryDown && (CurrSignalStrength < -75)){ + if (bTryDown && (CurrSignalStrength < -75)) { priv->TryDownCountLowData += TryDownTh; } } else if (priv->CurrentOperaRate == 72) { @@ -618,7 +617,7 @@ void StaRateAdaptive87SE(struct net_device *dev) bTryDown = true; } else if (((CurrRetryRate > 33) && (priv->LastRetryRate > 32)) && (CurrSignalStrength > -82)) { /* Cable Link */ bTryDown = true; - } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2 )) { + } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { bTryDown = true; priv->TryDownCountLowData += TryDownTh; } else if ((CurrRetryRate < 20) && (priv->LastRetryRate < 21)) { /* TO DO: need to consider (RSSI) */ @@ -641,8 +640,7 @@ void StaRateAdaptive87SE(struct net_device *dev) /* 2For 11Mbps */ if (CurrRetryRate > 95) { bTryDown = true; - } - else if ((CurrRetryRate < 29) && (priv->LastRetryRate < 30)) { /*TO DO: need to consider (RSSI) */ + } else if ((CurrRetryRate < 29) && (priv->LastRetryRate < 30)) { /*TO DO: need to consider (RSSI) */ bTryUp = true; } } else if (priv->CurrentOperaRate == 11) { @@ -672,7 +670,7 @@ void StaRateAdaptive87SE(struct net_device *dev) /* 1 Test Upgrading Tx Rate * Sometimes the cause of the low throughput (high retry rate) is the compatibility between the AP and NIC. * To test if the upper rate may cause lower retry rate, this mechanism randomly occurs to test upgrading tx rate. - */ + */ if (!bTryUp && !bTryDown && (priv->TryupingCount == 0) && (priv->TryDownCountLowData == 0) && priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate && priv->FailTxRateCount < 2) { if (jiffies % (CurrRetryRate + 101) == 0) { @@ -702,7 +700,7 @@ void StaRateAdaptive87SE(struct net_device *dev) if (priv->CurrentOperaRate == 22) bUpdateInitialGain = true; - /* + /* * The difference in throughput between 48Mbps and 36Mbps is 8M. * So, we must be careful in this rate scale. Isaiah 2008-02-15. */ @@ -718,7 +716,7 @@ void StaRateAdaptive87SE(struct net_device *dev) if (priv->CurrentOperaRate == 36) { priv->bUpdateARFR = true; write_nic_word(dev, ARFR, 0x0F8F); /* bypass 12/9/6 */ - } else if(priv->bUpdateARFR) { + } else if (priv->bUpdateARFR) { priv->bUpdateARFR = false; write_nic_word(dev, ARFR, 0x0FFF); /* set 1M ~ 54Mbps. */ } @@ -732,7 +730,7 @@ void StaRateAdaptive87SE(struct net_device *dev) } } else { if (priv->TryupingCount > 0) - priv->TryupingCount --; + priv->TryupingCount--; } if (bTryDown) { @@ -757,7 +755,7 @@ void StaRateAdaptive87SE(struct net_device *dev) priv->CurrentOperaRate = GetDegradeTxRate(dev, priv->CurrentOperaRate); /* Reduce chariot training time at weak signal strength situation. SD3 ED demand. */ - if ((CurrSignalStrength < -80) && (priv->CurrentOperaRate > 72 )) { + if ((CurrSignalStrength < -80) && (priv->CurrentOperaRate > 72)) { priv->CurrentOperaRate = 72; } @@ -781,8 +779,8 @@ void StaRateAdaptive87SE(struct net_device *dev) priv->TryDownCountLowData--; } - /* - * Keep the Tx fail rate count to equal to 0x15 at most. + /* + * Keep the Tx fail rate count to equal to 0x15 at most. * Reduce the fail count at least to 10 sec if tx rate is tending stable. */ if (priv->FailTxRateCount >= 0x15 || @@ -803,14 +801,14 @@ void StaRateAdaptive87SE(struct net_device *dev) if (u1bCck == CckTxPwrIdx) { if (u1bOfdm != (OfdmTxPwrIdx + 2)) { priv->bEnhanceTxPwr = true; - u1bOfdm = ((u1bOfdm + 2) > 35) ? 35: (u1bOfdm + 2); + u1bOfdm = ((u1bOfdm + 2) > 35) ? 35 : (u1bOfdm + 2); write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); } } else if (u1bCck < CckTxPwrIdx) { /* case 2: enter high power */ if (!priv->bEnhanceTxPwr) { priv->bEnhanceTxPwr = true; - u1bOfdm = ((u1bOfdm + 2) > 35) ? 35: (u1bOfdm + 2); + u1bOfdm = ((u1bOfdm + 2) > 35) ? 35 : (u1bOfdm + 2); write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); } } @@ -826,7 +824,7 @@ void StaRateAdaptive87SE(struct net_device *dev) /* case 2: enter high power */ else if (u1bCck < CckTxPwrIdx) { priv->bEnhanceTxPwr = false; - u1bOfdm = ((u1bOfdm - 2) > 0) ? (u1bOfdm - 2): 0; + u1bOfdm = ((u1bOfdm - 2) > 0) ? (u1bOfdm - 2) : 0; write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); } } @@ -851,7 +849,7 @@ SetInitialGain: else priv->InitialGain--; - printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n",priv->InitialGain, priv->CurrentOperaRate); + printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n", priv->InitialGain, priv->CurrentOperaRate); UpdateInitialGain(dev); } } else { /* OFDM */ @@ -859,7 +857,7 @@ SetInitialGain: priv->InitialGainBackUp = priv->InitialGain; priv->InitialGain++; - printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n",priv->InitialGain, priv->CurrentOperaRate); + printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n", priv->InitialGain, priv->CurrentOperaRate); UpdateInitialGain(dev); } } @@ -904,7 +902,7 @@ void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength) } else { /* Initialization case. */ priv->AdRxSignalStrength = SignalStrength; } - + if (priv->LastRxPktAntenna) /* Main antenna. */ priv->AdMainAntennaRxOkCnt++; else /* Aux antenna. */ @@ -943,7 +941,7 @@ bool SetAntenna8185(struct net_device *dev, u8 u1bAntennaIndex) break; } - if(bAntennaSwitched) + if (bAntennaSwitched) priv->CurrAntennaIndex = u1bAntennaIndex; return bAntennaSwitched; @@ -1000,8 +998,8 @@ void SwAntennaDiversity(struct net_device *dev) priv->AdRxSsThreshold = (priv->AdRxSignalStrength + priv->AdRxSsBeforeSwitched) / 2; priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? - priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold; - if(priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched) { + priv->AdMaxRxSsThreshold : priv->AdRxSsThreshold; + if (priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched) { /* Rx signal strength is not improved after we swtiched antenna. => Swich back. */ /* Increase Antenna Diversity checking period due to bad decision. */ priv->AdCheckPeriod *= 2; @@ -1083,7 +1081,7 @@ void SwAntennaDiversity(struct net_device *dev) priv->AdRxSsThreshold = (priv->AdRxSsThreshold + priv->AdRxSignalStrength) / 2; priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? - priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold;/* +by amy 080312 */ + priv->AdMaxRxSsThreshold : priv->AdRxSsThreshold;/* +by amy 080312 */ } /* Reduce Antenna Diversity checking period if possible. */ diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c index 978dc5f4f929..43383cf8b161 100644 --- a/drivers/staging/rtl8187se/r8185b_init.c +++ b/drivers/staging/rtl8187se/r8185b_init.c @@ -135,7 +135,7 @@ static void PlatformIOWrite2Byte(struct net_device *dev, u32 offset, u16 data) static void PlatformIOWrite4Byte(struct net_device *dev, u32 offset, u32 data) { if (offset == PhyAddr) { - /* For Base Band configuration. */ + /* For Base Band configuration. */ unsigned char cmdByte; unsigned long dataBytes; unsigned char idx; @@ -155,7 +155,7 @@ static void PlatformIOWrite4Byte(struct net_device *dev, u32 offset, u32 data) /* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */ for (idx = 0; idx < 30; idx++) { - /* Make sure command bit is clear before access it. */ + /* Make sure command bit is clear before access it. */ u1bTmp = PlatformIORead1Byte(dev, PhyAddr); if ((u1bTmp & BIT7) == 0) break; @@ -1296,8 +1296,8 @@ void rtl8185b_rx_enable(struct net_device *dev) if (dev->flags & IFF_PROMISC) DMESG("NIC in promisc mode"); - if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ - dev->flags & IFF_PROMISC) { + if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || dev->flags & + IFF_PROMISC) { priv->ReceiveConfig = priv->ReceiveConfig & (~RCR_APM); priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP; } diff --git a/drivers/staging/rtl8188eu/Makefile b/drivers/staging/rtl8188eu/Makefile index 1639a45da948..0bd32de44600 100644 --- a/drivers/staging/rtl8188eu/Makefile +++ b/drivers/staging/rtl8188eu/Makefile @@ -30,7 +30,6 @@ r8188eu-y := \ hal/HalPhyRf.o \ hal/HalPhyRf_8188e.o \ hal/HalPwrSeqCmd.o \ - hal/Hal8188EFWImg_CE.o \ hal/Hal8188EPwrSeq.o \ hal/Hal8188ERateAdaptive.o\ hal/hal_intf.o \ diff --git a/drivers/staging/rtl8188eu/TODO b/drivers/staging/rtl8188eu/TODO index e50aa50bdb47..f7f389c40e71 100644 --- a/drivers/staging/rtl8188eu/TODO +++ b/drivers/staging/rtl8188eu/TODO @@ -2,7 +2,6 @@ TODO: - find and remove remaining code valid only for 5 HGz. Most of the obvious ones have been removed, but things like channel > 14 still exist. - find and remove any code for other chips that is left over -- convert to external firmware - convert any remaining unusual variable types - find codes that can use %pM and %Nph formatting - checkpatch.pl fixes - most of the remaining ones are lines too long. Many diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 2c73823d2245..2c678f409573 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -348,7 +348,7 @@ void expire_timeout_chk(struct adapter *padapter) if (psta->state & WIFI_SLEEP_STATE) { if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { - /* to check if alive by another methods if staion is at ps mode. */ + /* to check if alive by another methods if station is at ps mode. */ psta->expire_to = pstapriv->expire_to; psta->state |= WIFI_STA_ALIVE_CHK_STATE; diff --git a/drivers/staging/rtl8188eu/core/rtw_br_ext.c b/drivers/staging/rtl8188eu/core/rtw_br_ext.c index fbca394cf4fc..9f40742ee5cf 100644 --- a/drivers/staging/rtl8188eu/core/rtw_br_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_br_ext.c @@ -527,7 +527,7 @@ int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method) case NAT25_CHECK: return -1; case NAT25_INSERT: - /* some muticast with source IP is all zero, maybe other case is illegal */ + /* some multicast with source IP is all zero, maybe other case is illegal */ /* in class A, B, C, host address is all zero or all one is illegal */ if (iph->saddr == 0) return 0; @@ -677,9 +677,8 @@ int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method) switch (method) { case NAT25_CHECK: if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) - DEBUG_INFO("NAT25: Check IPX skb_copy\n"); + DEBUG_INFO("NAT25: Check IPX skb_copy\n"); return 0; - return -1; case NAT25_INSERT: DEBUG_INFO("NAT25: Insert IPX, Dest =%08x,%02x%02x%02x%02x%02x%02x,%04x Source =%08x,%02x%02x%02x%02x%02x%02x,%04x\n", ipx->ipx_dest.net, diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c index 9632ef48fbc1..f45f4eddb741 100644 --- a/drivers/staging/rtl8188eu/core/rtw_cmd.c +++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c @@ -218,7 +218,7 @@ _func_enter_; _func_exit_; } -int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) +static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) { u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */ @@ -1162,7 +1162,7 @@ _func_enter_; else memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16); - /* jeff: set this becasue at least sw key is ready */ + /* jeff: set this because at least sw key is ready */ padapter->securitypriv.busetkipkey = true; res = rtw_enqueue_cmd(pcmdpriv, ph2c); @@ -1667,7 +1667,7 @@ static void traffic_status_watchdog(struct adapter *padapter) pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; } -void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz) +static void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz) { struct mlme_priv *pmlmepriv; diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c index 869434c4cf69..806f56f1c437 100644 --- a/drivers/staging/rtl8188eu/core/rtw_efuse.c +++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c @@ -159,7 +159,7 @@ Efuse_CalculateWordCnts(u8 word_en) /* */ /* Description: */ /* Execute E-Fuse read byte operation. */ -/* Refered from SD1 Richard. */ +/* Referred from SD1 Richard. */ /* */ /* Assumption: */ /* 1. Boot from E-Fuse and successfully auto-load. */ @@ -214,7 +214,7 @@ ReadEFuseByte( /* Description: */ /* 1. Execute E-Fuse read byte operation according as map offset and */ /* save to E-Fuse table. */ -/* 2. Refered from SD1 Richard. */ +/* 2. Referred from SD1 Richard. */ /* */ /* Assumption: */ /* 1. Boot from E-Fuse and successfully auto-load. */ @@ -542,7 +542,7 @@ u8 rtw_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) { u8 offset, word_en; u8 *map; - u8 newdata[PGPKT_DATA_SIZE]; + u8 newdata[PGPKT_DATA_SIZE + 1]; s32 i, idx; u8 ret = _SUCCESS; u16 mapLen = 0; @@ -564,7 +564,7 @@ u8 rtw_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) offset = (addr >> 3); word_en = 0xF; - _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE); + _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE + 1); i = addr & 0x7; /* index of one package */ idx = 0; /* data index */ @@ -634,7 +634,7 @@ u8 rtw_BT_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data { u8 offset, word_en; u8 *map; - u8 newdata[PGPKT_DATA_SIZE]; + u8 newdata[PGPKT_DATA_SIZE + 1]; s32 i, idx; u8 ret = _SUCCESS; u16 mapLen = 0; @@ -656,7 +656,7 @@ u8 rtw_BT_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data offset = (addr >> 3); word_en = 0xF; - _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE); + _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE + 1); i = addr & 0x7; /* index of one package */ idx = 0; /* data index */ diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c index 6fc77428e83a..e6f98fb8f113 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c @@ -1129,7 +1129,7 @@ void rtw_macaddr_cfg(u8 *mac_addr) mac[3] = 0x87; mac[4] = 0x00; mac[5] = 0x00; - /* use default mac addresss */ + /* use default mac address */ memcpy(mac_addr, mac, ETH_ALEN); DBG_88E("MAC Address from efuse error, assign default one !!!\n"); } diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index ea6607196d84..ac3535d33a45 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -557,7 +557,7 @@ _func_enter_; sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5; rssi_final = (src->Rssi+dst->Rssi*4)/5; } else { - /* bss info not receving from the right channel, use the original RX signal infos */ + /* bss info not receiving from the right channel, use the original RX signal infos */ ss_final = dst->PhyInfo.SignalStrength; sq_final = dst->PhyInfo.SignalQuality; rssi_final = dst->Rssi; @@ -636,7 +636,7 @@ _func_enter_; pnetwork->aid = 0; pnetwork->join_res = 0; - /* bss info not receving from the right channel */ + /* bss info not receiving from the right channel */ if (pnetwork->network.PhyInfo.SignalQuality == 101) pnetwork->network.PhyInfo.SignalQuality = 0; } else { @@ -656,7 +656,7 @@ _func_enter_; pnetwork->last_scanned = rtw_get_current_time(); - /* bss info not receving from the right channel */ + /* bss info not receiving from the right channel */ if (pnetwork->network.PhyInfo.SignalQuality == 101) pnetwork->network.PhyInfo.SignalQuality = 0; rtw_list_insert_tail(&(pnetwork->list), &(queue->queue)); @@ -670,7 +670,7 @@ _func_enter_; pnetwork->last_scanned = rtw_get_current_time(); - /* target.Reserved[0]== 1, means that scaned network is a bcn frame. */ + /* target.Reserved[0]== 1, means that scanned network is a bcn frame. */ if ((pnetwork->network.IELength > target->IELength) && (target->Reserved[0] == 1)) update_ie = false; @@ -1130,7 +1130,7 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str padapter->securitypriv.wps_ie_len = 0; } /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ - /* if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ + /* if A-MPDU Rx is enabled, resetting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ /* todo: check if AP can send A-MPDU packets */ for (i = 0; i < 16; i++) { /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ @@ -1210,7 +1210,7 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength); } -/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet) */ +/* Notes: the function could be > passive_level (the same context as Rx tasklet) */ /* pnetwork: returns from rtw_joinbss_event_callback */ /* ptarget_wlan: found from scanned_queue */ /* if join_res > 0, for (fw_state == WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. */ @@ -2177,7 +2177,7 @@ _func_enter_; _func_exit_; } -/* the fucntion is at passive_level */ +/* the function is at passive_level */ void rtw_joinbss_reset(struct adapter *padapter) { u8 threshold; @@ -2205,7 +2205,7 @@ void rtw_joinbss_reset(struct adapter *padapter) } } -/* the fucntion is >= passive_level */ +/* the function is >= passive_level */ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len) { u32 ielen, out_len; @@ -2273,7 +2273,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ return phtpriv->ht_option; } -/* the fucntion is > passive_level (in critical_section) */ +/* the function is > passive_level (in critical_section) */ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len) { u8 *p, max_ampdu_sz; @@ -2332,7 +2332,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len) else pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; } - /* switch to the 40M Hz mode accoring to the AP */ + /* switch to the 40M Hz mode according to the AP */ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) { case HT_EXTCHNL_OFFSET_UPPER: diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index 4b2eb8e9b562..9982dd0e2060 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -2349,7 +2349,7 @@ static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { /* Commented by Albert 2011/03/08 */ /* According to the P2P specification */ - /* if the sending device will be client, the P2P Capability should be reserved of group negotation response frame */ + /* if the sending device will be client, the P2P Capability should be reserved of group negotiation response frame */ p2pie[p2pielen++] = 0; } else { /* Be group owner or meet the error case */ @@ -6698,7 +6698,7 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str } } - /* mark bss info receving from nearby channel as SignalQuality 101 */ + /* mark bss info receiving from nearby channel as SignalQuality 101 */ if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) bssid->PhyInfo.SignalQuality = 101; return _SUCCESS; @@ -8110,7 +8110,7 @@ u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) Save_DM_Func_Flag(padapter); Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); - /* config the initial gain under scaning, need to write the BB registers */ + /* config the initial gain under scanning, need to write the BB registers */ #ifdef CONFIG_88EU_P2P if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) initialgain = 0x1E; diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 201165787362..9f0f30f7069a 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -204,11 +204,14 @@ void rtw_init_recvframe(union recv_frame *precvframe, struct recv_priv *precvpri int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_queue) { unsigned long irqL; - struct adapter *padapter = precvframe->u.hdr.adapter; - struct recv_priv *precvpriv = &padapter->recvpriv; + struct adapter *padapter; + struct recv_priv *precvpriv; _func_enter_; - + if (!precvframe) + return _FAIL; + padapter = precvframe->u.hdr.adapter; + precvpriv = &padapter->recvpriv; if (precvframe->u.hdr.pkt) { dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */ precvframe->u.hdr.pkt = NULL; @@ -1583,7 +1586,7 @@ _func_enter_; 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); @@ -1798,16 +1801,14 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); } - /* Indicat the packets to upper layer */ - if (sub_skb) { - /* Insert NAT2.5 RX here! */ - sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev); - sub_skb->dev = padapter->pnetdev; + /* Indicate the packets to upper layer */ + /* Insert NAT2.5 RX here! */ + sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev); + sub_skb->dev = padapter->pnetdev; - sub_skb->ip_summed = CHECKSUM_NONE; + sub_skb->ip_summed = CHECKSUM_NONE; - netif_rx(sub_skb); - } + netif_rx(sub_skb); } exit: diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c index 0f076d0cb5f8..e08845729772 100644 --- a/drivers/staging/rtl8188eu/core/rtw_security.c +++ b/drivers/staging/rtl8188eu/core/rtw_security.c @@ -916,7 +916,7 @@ _func_enter_; add1b[i] = 0x00; } - swap_halfs[0] = in[2]; /* Swap halfs */ + swap_halfs[0] = in[2]; /* Swap halves */ swap_halfs[1] = in[3]; swap_halfs[2] = in[0]; swap_halfs[3] = in[1]; diff --git a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c index c2977be92fb1..cd3c9a7c3044 100644 --- a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c @@ -267,9 +267,8 @@ _func_enter_; rtw_mfree_sta_priv_lock(pstapriv); - if (pstapriv->pallocated_stainfo_buf) { + if (pstapriv->pallocated_stainfo_buf) rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4); - } } _func_exit_; @@ -315,7 +314,7 @@ _func_enter_; rtw_list_insert_tail(&psta->hash_list, phash_list); - pstapriv->asoc_sta_count++ ; + pstapriv->asoc_sta_count++; _exit_critical_bh(&(pstapriv->sta_hash_lock), &irql2); @@ -419,7 +418,7 @@ _func_enter_; _cancel_timer_ex(&psta->addba_retry_timer); /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */ - for (i = 0; i < 16 ; i++) { + for (i = 0; i < 16; i++) { unsigned long irql; struct list_head *phead, *plist; union recv_frame *prframe; diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index 8018edd3d42e..153ec61493ab 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c @@ -80,7 +80,7 @@ int cckratesonly_included(unsigned char *rate, int ratelen) for (i = 0; i < ratelen; i++) { if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) - return false; + return false; } return true; @@ -766,7 +766,7 @@ void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) for (i = 0; i < (pIE->Length); i++) { if (i != 2) { - /* Got the endian issue here. */ + /* Got the endian issue here. */ pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]); } else { /* modify from fw by Thomas 2010/11/17 */ @@ -1096,13 +1096,13 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) } kfree(bssid); + _func_exit_; return _SUCCESS; _mismatch: kfree(bssid); - return _FAIL; - _func_exit_; + return _FAIL; } void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta) @@ -1186,7 +1186,7 @@ unsigned int should_forbid_n_rate(struct adapter *padapter) case _RSN_IE_2_: if ((_rtw_memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4)) || (_rtw_memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4))) - return false; + return false; default: break; } @@ -1368,21 +1368,21 @@ void update_tx_basic_rate(struct adapter *padapter, u8 wirelessmode) #ifdef CONFIG_88EU_P2P struct wifidirect_info *pwdinfo = &padapter->wdinfo; - /* Added by Albert 2011/03/22 */ - /* In the P2P mode, the driver should not support the b mode. */ - /* So, the Tx packet shouldn't use the CCK rate */ + /* Added by Albert 2011/03/22 */ + /* In the P2P mode, the driver should not support the b mode. */ + /* So, the Tx packet shouldn't use the CCK rate */ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) return; #endif /* CONFIG_88EU_P2P */ _rtw_memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); - if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) { + if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) memcpy(supported_rates, rtw_basic_rate_cck, 4); - } else if (wirelessmode & WIRELESS_11B) { + else if (wirelessmode & WIRELESS_11B) memcpy(supported_rates, rtw_basic_rate_mix, 7); - } else { + else memcpy(supported_rates, rtw_basic_rate_ofdm, 3); - } + if (wirelessmode & WIRELESS_11B) update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); @@ -1435,7 +1435,7 @@ unsigned char check_assoc_AP(u8 *pframe, uint len) DBG_88E("link to Airgo Cap\n"); return HT_IOT_PEER_AIRGO; } else if (_rtw_memcmp(pIE->data, EPIGRAM_OUI, 3)) { - epigram_vendor_flag = 1; + epigram_vendor_flag = 1; if (ralink_vendor_flag) { DBG_88E("link to Tenda W311R AP\n"); return HT_IOT_PEER_TENDA; diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c index bb5cd95c564e..a594e51d2e1c 100644 --- a/drivers/staging/rtl8188eu/core/rtw_xmit.c +++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c @@ -1556,7 +1556,7 @@ static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, str xmitframe_phead = get_list_head(pframe_queue); xmitframe_plist = get_next(xmitframe_phead); - while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) { + if (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) { pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); xmitframe_plist = get_next(xmitframe_plist); @@ -1564,12 +1564,7 @@ static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, str rtw_list_delete(&pxmitframe->list); ptxservq->qcnt--; - - break; - - pxmitframe = NULL; } - return pxmitframe; } diff --git a/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c b/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c deleted file mode 100644 index 95759bed5410..000000000000 --- a/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c +++ /dev/null @@ -1,1761 +0,0 @@ -/****************************************************************************** -* -* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of version 2 of the GNU General Public License 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 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., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA -* -* -******************************************************************************/ -#include "odm_precomp.h" - -const u8 Rtl8188EFwImgArray[Rtl8188EFWImgArrayLength] = { - 0xE1, 0x88, 0x10, 0x00, 0x0B, 0x00, 0x01, 0x00, - 0x01, 0x21, 0x11, 0x27, 0x30, 0x36, 0x00, 0x00, - 0x2D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x45, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xC1, 0x6F, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xA1, 0xE6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x56, 0xF7, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC2, 0xAF, 0x80, 0xFE, 0x32, 0x12, 0x42, 0x04, - 0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0, - 0xC2, 0x8C, 0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A, - 0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C, - 0xEC, 0x24, 0x89, 0xF8, 0xE6, 0xBC, 0x03, 0x02, - 0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00, - 0x40, 0xCE, 0x79, 0x04, 0x78, 0x80, 0x16, 0xE6, - 0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1, - 0x03, 0x44, 0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9, - 0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF, - 0x23, 0x24, 0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF, - 0x04, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30, - 0xE4, 0xF2, 0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50, - 0x20, 0x05, 0x0C, 0x74, 0x88, 0x25, 0x0C, 0xF8, - 0xE6, 0xFD, 0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C, - 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8, - 0x6D, 0x60, 0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80, - 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5, - 0x0C, 0x24, 0x89, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE, - 0x03, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD, - 0xF8, 0xE5, 0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0, - 0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x88, - 0xC8, 0xF6, 0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C, - 0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF, - 0xE6, 0x30, 0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F, - 0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F, - 0x08, 0x54, 0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF, - 0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x88, 0xA6, - 0x81, 0x74, 0x03, 0x60, 0x06, 0xFF, 0x08, 0x76, - 0xFF, 0xDF, 0xFB, 0x7F, 0x04, 0xE4, 0x78, 0x80, - 0xF6, 0x08, 0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81, - 0x76, 0x30, 0x90, 0x45, 0xDE, 0x74, 0x01, 0x93, - 0xC0, 0xE0, 0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89, - 0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2, - 0x8C, 0xD2, 0xAF, 0x22, 0x03, 0xEF, 0xD3, 0x94, - 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81, - 0x2F, 0x2F, 0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2, - 0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE, - 0x0C, 0xEE, 0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74, - 0x88, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18, - 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69, - 0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09, - 0x09, 0x80, 0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE, - 0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81, - 0xEE, 0xD3, 0x9F, 0x40, 0x22, 0x74, 0x88, 0x2E, - 0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02, - 0xA9, 0x81, 0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED, - 0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09, - 0xF7, 0x19, 0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF, - 0x24, 0x88, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F, - 0x04, 0x90, 0x45, 0xDE, 0x93, 0xF6, 0x08, 0xEF, - 0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3, - 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, - 0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4, - 0xC2, 0xAF, 0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF, - 0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x88, 0x2F, - 0xF8, 0xE6, 0xF5, 0x81, 0x02, 0x42, 0x4D, 0x50, - 0x2E, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xBF, 0x03, - 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74, - 0x88, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C, - 0x60, 0x08, 0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19, - 0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5, - 0x0C, 0xB5, 0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74, - 0x89, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01, - 0x0F, 0x74, 0x88, 0x2F, 0xF8, 0xA6, 0x01, 0x08, - 0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC, - 0x81, 0xED, 0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8, - 0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5, - 0x07, 0xDE, 0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF, - 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, - 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6, - 0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4, - 0xD2, 0xE2, 0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30, - 0xE2, 0x01, 0x0F, 0x02, 0x42, 0x4C, 0x8F, 0xF0, - 0xE4, 0xFF, 0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80, - 0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08, - 0xE6, 0x60, 0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50, - 0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6, - 0x60, 0x25, 0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10, - 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30, - 0xE2, 0x0C, 0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12, - 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC, - 0x4E, 0xF6, 0xD2, 0xAF, 0x02, 0x42, 0x4D, 0x7F, - 0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF, - 0x56, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF, - 0x22, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0, - 0xC5, 0xF0, 0xF8, 0xE5, 0x82, 0x15, 0x82, 0x70, - 0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, 0x22, 0xEF, - 0x5B, 0xFF, 0xEE, 0x5A, 0xFE, 0xED, 0x59, 0xFD, - 0xEC, 0x58, 0xFC, 0x22, 0xEF, 0x4B, 0xFF, 0xEE, - 0x4A, 0xFE, 0xED, 0x49, 0xFD, 0xEC, 0x48, 0xFC, - 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0, - 0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0xE2, 0xFC, 0x08, - 0xE2, 0xFD, 0x08, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, - 0x22, 0xE2, 0xFB, 0x08, 0xE2, 0xF9, 0x08, 0xE2, - 0xFA, 0x08, 0xE2, 0xCB, 0xF8, 0x22, 0xEC, 0xF2, - 0x08, 0xED, 0xF2, 0x08, 0xEE, 0xF2, 0x08, 0xEF, - 0xF2, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5, - 0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, 0xE0, 0xFB, - 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB, - 0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, 0xF0, 0x22, - 0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70, - 0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, 0xA3, 0xA3, - 0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88, - 0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, - 0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0x02, 0x45, - 0x8C, 0x02, 0x42, 0xDD, 0xE4, 0x93, 0xA3, 0xF8, - 0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01, - 0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, 0xE4, 0x93, - 0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, - 0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, - 0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, - 0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, - 0x10, 0x20, 0x40, 0x80, 0x90, 0x45, 0xD1, 0xE4, - 0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, 0xFF, 0x54, - 0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, - 0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, - 0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93, - 0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, - 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, - 0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, - 0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, - 0xBE, 0x00, 0x41, 0x82, 0x09, 0x00, 0x41, 0x82, - 0x0A, 0x00, 0x41, 0x82, 0x17, 0x00, 0x59, 0xE2, - 0x5C, 0x24, 0x5E, 0x5D, 0x5F, 0xA1, 0xC0, 0xE0, - 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, - 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, - 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, - 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xE6, - 0xF0, 0x74, 0x45, 0xA3, 0xF0, 0xD1, 0x35, 0x74, - 0xE6, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x45, - 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, - 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, - 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, - 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x00, 0x54, - 0xE0, 0x55, 0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55, - 0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, 0xF5, - 0x3B, 0xA3, 0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD, - 0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, 0x3A, - 0x7F, 0x55, 0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F, - 0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, 0x57, - 0x12, 0x32, 0x1E, 0x53, 0x91, 0xEF, 0x22, 0xC0, - 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, - 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, - 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, - 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, - 0x6F, 0xF0, 0x74, 0x46, 0xA3, 0xF0, 0x12, 0x6C, - 0x78, 0xE5, 0x41, 0x30, 0xE4, 0x04, 0x7F, 0x02, - 0x91, 0x27, 0xE5, 0x41, 0x30, 0xE6, 0x03, 0x12, - 0x6C, 0xD5, 0xE5, 0x43, 0x30, 0xE0, 0x03, 0x12, - 0x51, 0xC2, 0xE5, 0x43, 0x30, 0xE1, 0x03, 0x12, - 0x4D, 0x0C, 0xE5, 0x43, 0x30, 0xE2, 0x03, 0x12, - 0x4C, 0xC1, 0xE5, 0x43, 0x30, 0xE3, 0x03, 0x12, - 0x6C, 0xE2, 0xE5, 0x43, 0x30, 0xE4, 0x03, 0x12, - 0x6D, 0x04, 0xE5, 0x43, 0x30, 0xE5, 0x03, 0x12, - 0x6D, 0x33, 0xE5, 0x43, 0x30, 0xE6, 0x02, 0xF1, - 0x0F, 0xE5, 0x44, 0x30, 0xE1, 0x03, 0x12, 0x51, - 0x7F, 0x74, 0x6F, 0x04, 0x90, 0x01, 0xC4, 0xF0, - 0x74, 0x46, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, - 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, - 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, - 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, - 0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x13, 0x90, 0x81, - 0x27, 0xE0, 0x60, 0x0D, 0x90, 0x81, 0x2B, 0xE0, - 0x54, 0xFE, 0xF0, 0x54, 0x07, 0x70, 0x02, 0xF1, - 0x2A, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x90, 0x81, - 0x29, 0x30, 0xE0, 0x05, 0xE0, 0xFF, 0x02, 0x74, - 0x8F, 0xE0, 0xFF, 0x7D, 0x01, 0xD3, 0x10, 0xAF, - 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x13, 0xED, - 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x90, 0x82, 0x14, - 0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFE, 0xC4, 0x13, - 0x13, 0x54, 0x03, 0x30, 0xE0, 0x03, 0x02, 0x48, - 0xA0, 0xEE, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, - 0x30, 0xE0, 0x03, 0x02, 0x48, 0xA0, 0x90, 0x82, - 0x14, 0xE0, 0xFE, 0x6F, 0x70, 0x03, 0x02, 0x48, - 0xA0, 0xEF, 0x70, 0x03, 0x02, 0x48, 0x17, 0x24, - 0xFE, 0x70, 0x03, 0x02, 0x48, 0x50, 0x24, 0xFE, - 0x60, 0x51, 0x24, 0xFC, 0x70, 0x03, 0x02, 0x48, - 0x8B, 0x24, 0xFC, 0x60, 0x03, 0x02, 0x48, 0xA0, - 0xEE, 0xB4, 0x0E, 0x03, 0x12, 0x49, 0x5E, 0x90, - 0x82, 0x14, 0xE0, 0x70, 0x05, 0x7F, 0x01, 0x12, - 0x49, 0x93, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06, - 0x03, 0x12, 0x49, 0x34, 0x90, 0x82, 0x14, 0xE0, - 0xB4, 0x04, 0x0F, 0x90, 0x82, 0x13, 0xE0, 0xFF, - 0x60, 0x05, 0x12, 0x73, 0x75, 0x80, 0x03, 0x12, - 0x66, 0x26, 0x90, 0x82, 0x14, 0xE0, 0x64, 0x08, - 0x60, 0x03, 0x02, 0x48, 0xA0, 0x12, 0x73, 0xD3, - 0x02, 0x48, 0xA0, 0x90, 0x82, 0x14, 0xE0, 0x70, - 0x05, 0x7F, 0x01, 0x12, 0x49, 0x93, 0x90, 0x82, - 0x14, 0xE0, 0xB4, 0x06, 0x03, 0x12, 0x49, 0x34, - 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x09, 0x12, - 0x48, 0xA5, 0xBF, 0x01, 0x03, 0x12, 0x49, 0x5E, - 0x90, 0x82, 0x14, 0xE0, 0x64, 0x0C, 0x60, 0x02, - 0x01, 0xA0, 0x11, 0xA5, 0xEF, 0x64, 0x01, 0x60, - 0x02, 0x01, 0xA0, 0x11, 0xFA, 0x01, 0xA0, 0x90, - 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11, 0xA5, - 0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82, 0x14, - 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90, 0x82, - 0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5, 0xBF, - 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14, 0xE0, - 0x64, 0x04, 0x70, 0x5C, 0x12, 0x72, 0xF5, 0xEF, - 0x64, 0x01, 0x70, 0x54, 0x31, 0xBE, 0x80, 0x50, - 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11, - 0xA5, 0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82, - 0x14, 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90, - 0x82, 0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5, - 0xBF, 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14, - 0xE0, 0x70, 0x04, 0x7F, 0x01, 0x31, 0x93, 0x90, - 0x82, 0x14, 0xE0, 0xB4, 0x04, 0x1A, 0x12, 0x73, - 0xBB, 0x80, 0x15, 0x90, 0x82, 0x14, 0xE0, 0xB4, - 0x0C, 0x0E, 0x90, 0x81, 0x25, 0xE0, 0xFF, 0x13, - 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x02, 0x31, 0xB1, - 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD1, 0xAB, 0xEF, - 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, - 0x01, 0xF0, 0x80, 0x3D, 0x90, 0x81, 0x24, 0xE0, - 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, - 0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, - 0x28, 0xEF, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x08, - 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x19, - 0x90, 0x81, 0x29, 0xE0, 0xD3, 0x94, 0x04, 0x40, - 0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, - 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, - 0x22, 0x90, 0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F, - 0x00, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, - 0x70, 0x31, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFD, - 0xF0, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x7F, - 0x01, 0xF1, 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81, - 0x24, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A, - 0x74, 0x0E, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, - 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, - 0xB8, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x25, 0xE0, - 0x90, 0x06, 0x04, 0x20, 0xE0, 0x0C, 0xE0, 0x44, - 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, - 0x80, 0x0E, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81, - 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0, - 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, 0x81, - 0x25, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x08, 0x90, - 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x80, 0x1E, 0x90, - 0x06, 0x04, 0xE0, 0x44, 0x40, 0xF0, 0xE0, 0x44, - 0x80, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, - 0x90, 0x05, 0x27, 0xE0, 0x44, 0x80, 0xF0, 0x90, - 0x81, 0x23, 0x74, 0x04, 0xF0, 0x90, 0x05, 0x22, - 0xE4, 0xF0, 0x22, 0x90, 0x82, 0x15, 0xEF, 0xF0, - 0x12, 0x54, 0x65, 0x90, 0x82, 0x15, 0xE0, 0x60, - 0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, - 0x2A, 0x74, 0x04, 0xF0, 0x90, 0x81, 0x23, 0xF0, - 0x22, 0x31, 0xE3, 0x90, 0x81, 0x2A, 0x74, 0x08, - 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05, - 0x22, 0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x01, - 0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0x51, - 0x57, 0x31, 0xE3, 0xE4, 0x90, 0x81, 0x2A, 0xF0, - 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05, 0x22, - 0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x85, 0xBB, - 0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F, - 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, - 0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14, - 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90, - 0x81, 0xF9, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, - 0x00, 0xE4, 0xFD, 0xFF, 0x12, 0x55, 0x1C, 0x7F, - 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44, - 0x80, 0xFC, 0x90, 0x82, 0x05, 0x12, 0x20, 0xCE, - 0x90, 0x82, 0x05, 0x12, 0x44, 0xD9, 0x90, 0x85, - 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, - 0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F, - 0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05, - 0x53, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0x90, 0x01, - 0x34, 0x74, 0x40, 0xF0, 0xFD, 0xE4, 0xFF, 0x74, - 0x3D, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, - 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, - 0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, - 0xC3, 0xC0, 0xD0, 0xE4, 0x90, 0x81, 0xCB, 0xF0, - 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, - 0x81, 0x1F, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0, - 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F, - 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x04, - 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81, - 0x1F, 0xF0, 0xEE, 0x54, 0x08, 0xFE, 0xEF, 0x54, - 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, - 0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, 0x4D, 0xFF, - 0x90, 0x81, 0x1F, 0xF0, 0xEE, 0x54, 0x20, 0xFE, - 0xEF, 0x54, 0xDF, 0x4E, 0xF0, 0x12, 0x1F, 0xA4, - 0xC3, 0x13, 0x20, 0xE0, 0x02, 0x61, 0x5E, 0x90, - 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x6D, 0x90, - 0x81, 0xCB, 0x74, 0x21, 0xF0, 0xEF, 0x13, 0x13, - 0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E, 0x90, - 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80, 0x0C, - 0xE4, 0x90, 0x81, 0x20, 0xF0, 0xA3, 0xF0, 0x7D, - 0x40, 0xFF, 0x91, 0x26, 0x90, 0x81, 0x1F, 0xE0, - 0xFD, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, - 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x12, 0xF0, - 0xED, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x07, 0x90, - 0x81, 0xCB, 0xE0, 0x44, 0x14, 0xF0, 0x90, 0x81, - 0x1F, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0x30, 0xE0, - 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x80, 0xF0, - 0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27, 0xF0, - 0x90, 0x81, 0x22, 0xE0, 0x60, 0x02, 0x81, 0x17, - 0x7F, 0x01, 0x80, 0x15, 0x90, 0x81, 0xCB, 0x74, - 0x01, 0xF0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81, - 0x22, 0xE0, 0x64, 0x04, 0x60, 0x02, 0x81, 0x17, - 0xFF, 0x12, 0x53, 0x0E, 0x81, 0x17, 0x90, 0x81, - 0x1F, 0xE0, 0xFF, 0x20, 0xE0, 0x02, 0x61, 0xE7, - 0x90, 0x81, 0xCB, 0x74, 0x31, 0xF0, 0xEF, 0x13, - 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E, - 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80, - 0x06, 0x7D, 0x40, 0xE4, 0xFF, 0x91, 0x26, 0x90, - 0x81, 0x1F, 0xE0, 0xFD, 0x13, 0x13, 0x13, 0x54, - 0x1F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, - 0x44, 0x02, 0xF0, 0xED, 0xC4, 0x54, 0x0F, 0x30, - 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x04, - 0xF0, 0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27, - 0xF0, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x70, - 0x1D, 0xFD, 0x7F, 0x04, 0x12, 0x47, 0x3D, 0x12, - 0x51, 0x73, 0xBF, 0x01, 0x09, 0x90, 0x81, 0x29, - 0xE0, 0xFF, 0x7D, 0x01, 0x80, 0x03, 0xE4, 0xFD, - 0xFF, 0x12, 0x47, 0x3D, 0x80, 0x41, 0x90, 0x81, - 0x2A, 0xE0, 0x90, 0x81, 0x23, 0xF0, 0x90, 0x05, - 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x80, 0x30, 0x90, - 0x81, 0xCB, 0x74, 0x01, 0xF0, 0x90, 0x05, 0x27, - 0xF0, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x06, - 0x7D, 0x01, 0x7F, 0x04, 0x80, 0x0B, 0x90, 0x81, - 0x23, 0xE0, 0xB4, 0x08, 0x07, 0x7D, 0x01, 0x7F, - 0x0C, 0x12, 0x47, 0x3D, 0xD1, 0x34, 0x90, 0x81, - 0x29, 0x12, 0x47, 0x39, 0x12, 0x5A, 0xA7, 0xD0, - 0xD0, 0x92, 0xAF, 0x22, 0x7D, 0x02, 0x7F, 0x02, - 0x91, 0x26, 0x7D, 0x01, 0x7F, 0x02, 0x74, 0x3D, - 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, - 0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, - 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xEF, 0x70, - 0x37, 0x7D, 0x78, 0x7F, 0x02, 0x91, 0x26, 0x7D, - 0x02, 0x7F, 0x03, 0x91, 0x26, 0x7D, 0xC8, 0x7F, - 0x02, 0x12, 0x71, 0x8F, 0x90, 0x01, 0x57, 0xE4, - 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x7D, - 0x01, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x90, 0x81, - 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, - 0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, 0x22, - 0x90, 0x01, 0x36, 0x74, 0x78, 0xF0, 0xA3, 0x74, - 0x02, 0xF0, 0x7D, 0x78, 0xFF, 0x51, 0x57, 0x7D, - 0x02, 0x7F, 0x03, 0x51, 0x57, 0x90, 0x06, 0x0A, - 0xE0, 0x44, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xA3, - 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x80, 0xDE, - 0xE0, 0xB4, 0x01, 0x15, 0x90, 0x81, 0x25, 0xE0, - 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, - 0xE2, 0x0E, 0x7D, 0x01, 0x7F, 0x04, 0x02, 0x47, - 0x3D, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0, - 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, - 0x08, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, - 0x3A, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x04, 0xEF, - 0x30, 0xE0, 0x0A, 0x90, 0x81, 0x2A, 0xE0, 0x64, - 0x02, 0x60, 0x28, 0xB1, 0x83, 0x90, 0x81, 0x25, - 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, - 0x14, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0, - 0x6F, 0x70, 0x0A, 0xF1, 0xCD, 0x91, 0x1C, 0x90, - 0x81, 0x2E, 0xE0, 0x14, 0xF0, 0x90, 0x01, 0xE6, - 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0, - 0x30, 0xE0, 0x06, 0x90, 0x81, 0x21, 0x74, 0x01, - 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x45, 0x90, - 0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54, - 0x1F, 0x30, 0xE0, 0x12, 0x90, 0x01, 0x3B, 0xE0, - 0x30, 0xE4, 0x0B, 0x91, 0x1C, 0x90, 0x81, 0x2D, - 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x82, - 0x0B, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, - 0xC3, 0x90, 0x82, 0x0C, 0xE0, 0x94, 0x80, 0x90, - 0x82, 0x0B, 0xE0, 0x64, 0x80, 0x94, 0x80, 0x40, - 0x0B, 0x90, 0x01, 0x98, 0xE0, 0x54, 0xFE, 0xF0, - 0xE0, 0x44, 0x01, 0xF0, 0x12, 0x75, 0xF8, 0xD1, - 0xD6, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x0C, - 0xE4, 0xF5, 0x1D, 0xA3, 0xF1, 0xFB, 0x90, 0x01, - 0x57, 0x74, 0x05, 0xF0, 0x90, 0x01, 0xBE, 0xE0, - 0x04, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, - 0x01, 0x60, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x27, - 0xE0, 0x70, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x26, - 0xE0, 0xC4, 0x54, 0x0F, 0x64, 0x01, 0x70, 0x22, - 0x90, 0x06, 0xAB, 0xE0, 0x90, 0x81, 0x2E, 0xF0, - 0x90, 0x06, 0xAA, 0xE0, 0x90, 0x81, 0x2D, 0xF0, - 0xA3, 0xE0, 0xFF, 0x70, 0x08, 0x90, 0x81, 0x2D, - 0xE0, 0xFE, 0xFF, 0x80, 0x00, 0x90, 0x81, 0x2E, - 0xEF, 0xF0, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, - 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, - 0x32, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, - 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, - 0x02, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, - 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x26, 0xE0, - 0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02, - 0x80, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, - 0x05, 0x12, 0x6D, 0xF2, 0x80, 0x03, 0x12, 0x6E, - 0xC9, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x13, - 0x54, 0x1F, 0x30, 0xE0, 0x0E, 0x90, 0x81, 0x2D, - 0xE0, 0xFF, 0xA3, 0xE0, 0xB5, 0x07, 0x04, 0xF1, - 0xCD, 0x91, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xC3, - 0x13, 0x20, 0xE0, 0x07, 0x90, 0x81, 0x25, 0xE0, - 0x44, 0x04, 0xF0, 0x22, 0xD1, 0xAB, 0xEF, 0x70, - 0x02, 0xD1, 0x3C, 0x22, 0x90, 0x81, 0x27, 0xE0, - 0x64, 0x01, 0x70, 0x66, 0x90, 0x81, 0x26, 0xE0, - 0x54, 0x0F, 0x60, 0x51, 0x90, 0x81, 0x2A, 0xE0, - 0x70, 0x03, 0xFF, 0x31, 0x93, 0x90, 0x81, 0x2A, - 0xE0, 0x64, 0x0C, 0x60, 0x03, 0x12, 0x66, 0x26, - 0x90, 0x01, 0x5B, 0xE4, 0xF0, 0x90, 0x01, 0x3C, - 0x74, 0x04, 0xF0, 0xD1, 0xAB, 0xEF, 0x64, 0x01, - 0x60, 0x38, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, - 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, - 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x50, - 0x05, 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, - 0x06, 0x92, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x24, - 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x90, 0x81, 0x2A, - 0xE0, 0x70, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12, - 0x47, 0x3D, 0x22, 0x90, 0x04, 0x1A, 0xE0, 0xF4, - 0x60, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x04, 0x1B, - 0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, 0x60, - 0x02, 0x7F, 0x00, 0x22, 0x12, 0x50, 0x60, 0x90, - 0x81, 0x2D, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, - 0x7D, 0x02, 0x7F, 0x02, 0x51, 0x57, 0x90, 0x81, - 0x42, 0xE0, 0x30, 0xE0, 0x2D, 0x90, 0x80, 0xDE, - 0xE0, 0xB4, 0x01, 0x26, 0x90, 0x82, 0x17, 0xE0, - 0x04, 0xF0, 0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x81, - 0x44, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x82, 0x17, - 0xF0, 0x90, 0x81, 0x44, 0xE0, 0xFF, 0x90, 0x81, - 0x43, 0xE0, 0xB5, 0x07, 0x05, 0xE4, 0xA3, 0xF0, - 0xF1, 0x0B, 0x22, 0xE4, 0xFF, 0x8F, 0x53, 0x90, - 0x04, 0x1D, 0xE0, 0x60, 0x19, 0x90, 0x05, 0x22, - 0xE0, 0xF5, 0x56, 0x74, 0xFF, 0xF0, 0xF1, 0x3A, - 0xBF, 0x01, 0x03, 0x12, 0x74, 0xFB, 0x90, 0x05, - 0x22, 0xE5, 0x56, 0xF0, 0x80, 0x03, 0x12, 0x74, - 0xFB, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F, - 0x01, 0x22, 0xE4, 0x90, 0x82, 0x0F, 0xF0, 0xA3, - 0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3, - 0xE0, 0x70, 0x0B, 0xA3, 0xE0, 0x70, 0x07, 0xA3, - 0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90, - 0x82, 0x10, 0xE0, 0x94, 0xE8, 0x90, 0x82, 0x0F, - 0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0, - 0xE0, 0x44, 0x20, 0xF0, 0x7F, 0x00, 0x22, 0x7F, - 0x32, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x82, - 0x0F, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, - 0x80, 0xBF, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, - 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x3F, 0xF0, - 0xEF, 0x60, 0x1D, 0x74, 0x21, 0x2D, 0xF5, 0x82, - 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x10, - 0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, - 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x22, - 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, - 0xF5, 0x83, 0xE0, 0x54, 0xEF, 0xF0, 0x74, 0x1F, - 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, - 0xE0, 0x44, 0x40, 0xF0, 0x22, 0xEF, 0x14, 0x90, - 0x05, 0x73, 0xF0, 0x90, 0x01, 0x3F, 0x74, 0x10, - 0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x45, 0x2F, 0xF8, - 0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, - 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, - 0x22, 0xE0, 0x44, 0x02, 0xF0, 0xE4, 0xF5, 0x1D, - 0x90, 0x81, 0x39, 0xE0, 0xF5, 0x1E, 0xE4, 0xFB, - 0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x8E, 0x19, 0x8F, - 0x1A, 0xE5, 0x1E, 0x54, 0x07, 0xC4, 0x33, 0x54, - 0xE0, 0x85, 0x19, 0x83, 0x85, 0x1A, 0x82, 0xF0, - 0xE5, 0x1D, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, - 0xFF, 0xE5, 0x1E, 0x13, 0x13, 0x13, 0x54, 0x1F, - 0x4F, 0xA3, 0xF0, 0xEB, 0x54, 0x07, 0xC4, 0x33, - 0x54, 0xE0, 0xFF, 0xE5, 0x1D, 0x13, 0x13, 0x13, - 0x54, 0x1F, 0x4F, 0x85, 0x1A, 0x82, 0x85, 0x19, - 0x83, 0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0C, 0x85, - 0x1A, 0x82, 0x8E, 0x83, 0xA3, 0xA3, 0xA3, 0x74, - 0x03, 0xF0, 0x22, 0x85, 0x1A, 0x82, 0x85, 0x19, - 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x01, 0xF0, 0x22, - 0xE4, 0x90, 0x81, 0x4D, 0xF0, 0x90, 0x81, 0x27, - 0xE0, 0x60, 0x58, 0x90, 0x80, 0xDE, 0xE0, 0x64, - 0x01, 0x70, 0x50, 0x90, 0x81, 0x4D, 0x04, 0xF0, - 0xE4, 0x90, 0x81, 0x2E, 0xF0, 0x90, 0x81, 0x1F, - 0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0, - 0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4D, 0xF0, - 0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4D, - 0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x60, 0x24, 0x90, - 0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5, - 0x1D, 0x90, 0x81, 0x2F, 0x12, 0x4F, 0xFB, 0x90, - 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, - 0xE0, 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04, - 0x12, 0x47, 0x3D, 0x22, 0xE4, 0x90, 0x81, 0x4C, - 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x02, 0x21, - 0x72, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60, - 0x02, 0x21, 0x72, 0x90, 0x81, 0x26, 0xE0, 0xFF, - 0xC4, 0x54, 0x0F, 0x60, 0x22, 0x24, 0xFE, 0x60, - 0x03, 0x04, 0x70, 0x21, 0x90, 0x81, 0x2E, 0xE0, - 0x14, 0xF0, 0xE0, 0xFF, 0x60, 0x06, 0x90, 0x81, - 0x30, 0xE0, 0x60, 0x11, 0xEF, 0x70, 0x08, 0x90, - 0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x80, 0x00, 0x90, - 0x81, 0x4C, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x1F, - 0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0, - 0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4C, 0xF0, - 0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4C, - 0xF0, 0x90, 0x81, 0x4C, 0xE0, 0x60, 0x43, 0x90, - 0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, - 0x30, 0xE0, 0x60, 0x03, 0xB4, 0x01, 0x09, 0xE4, - 0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x80, 0x0D, - 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x75, - 0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, 0x90, 0x81, - 0x2F, 0xE0, 0x2F, 0x12, 0x4F, 0xFC, 0x90, 0x01, - 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0, - 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12, - 0x47, 0x3D, 0x22, 0x90, 0x05, 0x43, 0xE0, 0x7F, - 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x22, 0x90, - 0x81, 0x27, 0xE0, 0x70, 0x07, 0x90, 0x81, 0x1F, - 0xE0, 0x30, 0xE0, 0x11, 0x90, 0x81, 0x1F, 0xE0, - 0x30, 0xE0, 0x07, 0x31, 0x73, 0xBF, 0x01, 0x05, - 0x41, 0x5B, 0x12, 0x4E, 0x3C, 0x22, 0xD3, 0x10, - 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x1E, - 0xE0, 0xB4, 0x01, 0x04, 0x7F, 0x04, 0x80, 0x0B, - 0x31, 0x73, 0xBF, 0x01, 0x04, 0x7F, 0x01, 0x80, - 0x02, 0x7F, 0x02, 0x71, 0x0E, 0xD0, 0xD0, 0x92, - 0xAF, 0x22, 0x90, 0x81, 0x4B, 0xE0, 0x60, 0x0F, - 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x02, - 0xF0, 0x90, 0x05, 0xFC, 0xE0, 0x04, 0xF0, 0x90, - 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x10, 0xA3, 0x74, - 0x01, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0xC3, - 0x13, 0x30, 0xE0, 0x02, 0x31, 0x9E, 0x11, 0xC4, - 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x07, 0x91, - 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, - 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3D, 0x90, - 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02, - 0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, 0x00, - 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70, - 0x23, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x21, - 0x9E, 0x51, 0x45, 0x90, 0x81, 0x23, 0xE0, 0xB4, - 0x08, 0x06, 0xE4, 0xFD, 0x7F, 0x0C, 0x80, 0x09, - 0x90, 0x81, 0x23, 0xE0, 0x70, 0x06, 0xFD, 0x7F, - 0x04, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x81, 0x1E, - 0xE0, 0xB4, 0x01, 0x0F, 0x90, 0x81, 0x23, 0xE0, - 0x64, 0x02, 0x60, 0x07, 0x7D, 0x01, 0x7F, 0x02, - 0x12, 0x47, 0x3D, 0x90, 0x81, 0x27, 0xE0, 0x64, - 0x02, 0x60, 0x14, 0x90, 0x81, 0x26, 0xE0, 0x54, - 0x0F, 0x60, 0x0C, 0x12, 0x4E, 0xAB, 0xEF, 0x70, - 0x06, 0xFD, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x22, - 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3F, - 0x90, 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, - 0x02, 0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, - 0x00, 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, - 0x70, 0x25, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, - 0x21, 0x9E, 0x12, 0x74, 0xAC, 0x90, 0x81, 0x23, - 0xE0, 0xB4, 0x0C, 0x06, 0xE4, 0xFD, 0x7F, 0x08, - 0x80, 0x0A, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x04, - 0x06, 0xE4, 0xFD, 0xFF, 0x12, 0x47, 0x3D, 0x22, - 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, - 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x1F, 0xA4, - 0xFF, 0x90, 0x81, 0x1E, 0xF0, 0xBF, 0x01, 0x12, - 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00, - 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x21, - 0x80, 0x1D, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, - 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, - 0x60, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x20, 0xE0, - 0x06, 0xE4, 0xFF, 0x71, 0x0E, 0x80, 0x02, 0x31, - 0x9E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, - 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x22, - 0xE0, 0x90, 0x82, 0x16, 0xF0, 0x6F, 0x70, 0x02, - 0x81, 0x04, 0xEF, 0x14, 0x60, 0x3E, 0x14, 0x60, - 0x62, 0x14, 0x70, 0x02, 0x61, 0xB8, 0x14, 0x70, - 0x02, 0x61, 0xDF, 0x24, 0x04, 0x60, 0x02, 0x81, - 0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, - 0x04, 0x91, 0x41, 0x81, 0x04, 0xEF, 0xB4, 0x02, - 0x04, 0x91, 0x50, 0x81, 0x04, 0x90, 0x82, 0x16, - 0xE0, 0xFF, 0xB4, 0x03, 0x04, 0x91, 0x54, 0x81, - 0x04, 0xEF, 0x64, 0x01, 0x60, 0x02, 0x81, 0x04, - 0x91, 0x43, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0, - 0xFF, 0xB4, 0x04, 0x04, 0x91, 0xF3, 0x81, 0x04, - 0xEF, 0xB4, 0x02, 0x04, 0x91, 0x58, 0x81, 0x04, - 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x04, - 0x91, 0xE8, 0x81, 0x04, 0xEF, 0x70, 0x7D, 0x91, - 0x2B, 0x80, 0x79, 0x90, 0x82, 0x16, 0xE0, 0xB4, - 0x04, 0x05, 0x12, 0x74, 0x60, 0x80, 0x6D, 0x90, - 0x82, 0x16, 0xE0, 0xB4, 0x01, 0x04, 0x91, 0x21, - 0x80, 0x62, 0x90, 0x82, 0x16, 0xE0, 0xB4, 0x03, - 0x05, 0x12, 0x74, 0x71, 0x80, 0x56, 0x90, 0x82, - 0x16, 0xE0, 0x70, 0x50, 0x91, 0x1F, 0x80, 0x4C, - 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, 0x05, - 0x12, 0x74, 0x4C, 0x80, 0x3F, 0xEF, 0xB4, 0x01, - 0x04, 0x91, 0x34, 0x80, 0x37, 0xEF, 0xB4, 0x02, - 0x04, 0x91, 0xDF, 0x80, 0x2F, 0x90, 0x82, 0x16, - 0xE0, 0x70, 0x29, 0x91, 0x32, 0x80, 0x25, 0x90, - 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x05, 0x12, - 0x74, 0x7B, 0x80, 0x18, 0xEF, 0xB4, 0x01, 0x04, - 0x91, 0x0B, 0x80, 0x10, 0xEF, 0xB4, 0x02, 0x04, - 0xB1, 0x06, 0x80, 0x08, 0x90, 0x82, 0x16, 0xE0, - 0x70, 0x02, 0x91, 0x09, 0xD0, 0xD0, 0x92, 0xAF, - 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74, 0x6F, - 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, - 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0x91, - 0x2B, 0x12, 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74, - 0x02, 0xF0, 0x22, 0x90, 0x81, 0x22, 0x74, 0x01, - 0xF0, 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74, - 0xFF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, - 0x22, 0x91, 0xF3, 0x90, 0x05, 0x27, 0xE0, 0x54, - 0xBF, 0xF0, 0xE4, 0x90, 0x81, 0x22, 0xF0, 0x22, - 0x91, 0x58, 0x80, 0xEF, 0x91, 0xE8, 0x80, 0xEB, - 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, - 0x81, 0x22, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, - 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0x01, 0xE0, - 0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF, - 0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, 0xF0, 0x90, - 0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E, - 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x54, 0x7F, 0xFC, - 0x90, 0x82, 0x01, 0x12, 0x20, 0xCE, 0x90, 0x82, - 0x01, 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, - 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, - 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, - 0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, - 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, - 0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, - 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xF9, 0x12, 0x20, - 0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF, - 0xB1, 0x1C, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x91, - 0x65, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22, - 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x22, - 0x04, 0xF0, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0, - 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, - 0x81, 0x22, 0x74, 0x01, 0xF0, 0x22, 0x91, 0x65, - 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x05, - 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, - 0x74, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, - 0xC3, 0xC0, 0xD0, 0xC0, 0x07, 0xC0, 0x05, 0x90, - 0x81, 0xF9, 0x12, 0x44, 0xD9, 0x90, 0x81, 0xE5, - 0x12, 0x20, 0xCE, 0xD0, 0x05, 0xD0, 0x07, 0x12, - 0x60, 0xF5, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, - 0x81, 0xC8, 0x12, 0x45, 0x1F, 0xEF, 0x12, 0x45, - 0x28, 0x55, 0x71, 0x00, 0x55, 0x7A, 0x01, 0x55, - 0x83, 0x02, 0x55, 0x8B, 0x03, 0x55, 0x94, 0x04, - 0x55, 0x9C, 0x20, 0x55, 0xA4, 0x21, 0x55, 0xAD, - 0x23, 0x55, 0xB5, 0x24, 0x55, 0xBE, 0x25, 0x55, - 0xC7, 0x26, 0x55, 0xCF, 0xC0, 0x00, 0x00, 0x55, - 0xD8, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, - 0x6A, 0xB0, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, - 0x02, 0x65, 0x81, 0x90, 0x81, 0xC8, 0x12, 0x45, - 0x16, 0x41, 0xC0, 0x90, 0x81, 0xC8, 0x12, 0x45, - 0x16, 0x02, 0x75, 0xD8, 0x90, 0x81, 0xC8, 0x12, - 0x45, 0x16, 0x80, 0x44, 0x90, 0x81, 0xC8, 0x12, - 0x45, 0x16, 0xC1, 0x4B, 0x90, 0x81, 0xC8, 0x12, - 0x45, 0x16, 0x02, 0x6A, 0xF8, 0x90, 0x81, 0xC8, - 0x12, 0x45, 0x16, 0xE1, 0xE1, 0x90, 0x81, 0xC8, - 0x12, 0x45, 0x16, 0x02, 0x4A, 0x6C, 0x90, 0x81, - 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x3E, 0x90, - 0x81, 0xC8, 0x12, 0x45, 0x16, 0x80, 0x3E, 0x90, - 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x4E, - 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22, - 0x12, 0x5A, 0x4B, 0x12, 0x1F, 0xA4, 0xFF, 0x54, - 0x01, 0xFE, 0x90, 0x81, 0x45, 0xE0, 0x54, 0xFE, - 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x14, - 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, - 0x46, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, - 0x90, 0x81, 0x47, 0xF0, 0x22, 0x12, 0x1F, 0xA4, - 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x3F, 0xE0, - 0x54, 0xFE, 0x4E, 0xF0, 0x90, 0x00, 0x01, 0x12, - 0x1F, 0xBD, 0xFE, 0x90, 0x05, 0x54, 0xE0, 0xC3, - 0x9E, 0x90, 0x81, 0x40, 0xF0, 0xEF, 0x20, 0xE0, - 0x07, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, - 0x90, 0x81, 0x3F, 0xE0, 0x54, 0x01, 0x90, 0x01, - 0xBC, 0xF0, 0x90, 0x81, 0x40, 0xE0, 0x90, 0x01, - 0xBD, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54, - 0x7F, 0x90, 0x81, 0x27, 0xF0, 0xEF, 0xC4, 0x13, - 0x13, 0x13, 0x54, 0x01, 0xA3, 0xF0, 0x90, 0x00, - 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x54, 0xF0, 0xC4, - 0x54, 0x0F, 0xFE, 0x90, 0x81, 0x26, 0xE0, 0x54, - 0xF0, 0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, - 0xBD, 0x54, 0x01, 0x25, 0xE0, 0xFE, 0x90, 0x81, - 0x24, 0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0xEF, 0x54, - 0x0F, 0xC4, 0x54, 0xF0, 0xFF, 0x90, 0x81, 0x26, - 0xE0, 0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, 0x04, - 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x29, 0xF0, 0xD1, - 0xC6, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, - 0x01, 0xB8, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x90, - 0x01, 0xBA, 0xF0, 0x90, 0x81, 0x29, 0xE0, 0x90, - 0x01, 0xBB, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, - 0x0F, 0x90, 0x01, 0xBE, 0xF0, 0x22, 0x90, 0x81, - 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x72, 0xB3, 0x90, - 0x81, 0x27, 0xE0, 0xFF, 0x12, 0x4C, 0x3E, 0x90, - 0x81, 0x27, 0xE0, 0x60, 0x19, 0x90, 0x81, 0xCB, - 0x12, 0x45, 0x16, 0x90, 0x00, 0x01, 0x12, 0x1F, - 0xBD, 0x54, 0x0F, 0xFF, 0x90, 0x00, 0x02, 0x12, - 0x1F, 0xBD, 0xFD, 0x12, 0x72, 0xC4, 0x22, 0xC0, - 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, - 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, - 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, - 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, - 0xF7, 0xF0, 0x74, 0x56, 0xA3, 0xF0, 0x12, 0x6C, - 0xA5, 0xE5, 0x49, 0x30, 0xE1, 0x03, 0x12, 0x6F, - 0x79, 0xE5, 0x49, 0x30, 0xE2, 0x02, 0xF1, 0xA5, - 0xE5, 0x49, 0x30, 0xE3, 0x03, 0x12, 0x6F, 0x8D, - 0xE5, 0x4A, 0x30, 0xE0, 0x03, 0x12, 0x6F, 0xC9, - 0xE5, 0x4A, 0x30, 0xE4, 0x03, 0x12, 0x70, 0x22, - 0xE5, 0x4B, 0x30, 0xE1, 0x02, 0x51, 0x78, 0xE5, - 0x4B, 0x30, 0xE0, 0x02, 0x31, 0xFF, 0xE5, 0x4B, - 0x30, 0xE3, 0x02, 0xF1, 0xE0, 0xE5, 0x4C, 0x30, - 0xE1, 0x05, 0x7F, 0x03, 0x12, 0x44, 0x27, 0xE5, - 0x4C, 0x30, 0xE4, 0x03, 0x12, 0x4E, 0xC4, 0xE5, - 0x4C, 0x30, 0xE5, 0x03, 0x12, 0x70, 0x38, 0xE5, - 0x4C, 0x30, 0xE6, 0x03, 0x12, 0x70, 0xCE, 0x74, - 0xF7, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x56, - 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, - 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, - 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, - 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x81, 0x27, - 0xE0, 0x60, 0x34, 0x90, 0x06, 0x92, 0xE0, 0x30, - 0xE0, 0x23, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, - 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, - 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x11, 0x05, - 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, 0x06, - 0x92, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x24, - 0xE0, 0x54, 0xF7, 0xF0, 0x12, 0x47, 0x2A, 0x22, - 0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x31, 0xF0, - 0x22, 0x90, 0x01, 0xC8, 0xE4, 0xF0, 0xA3, 0xF0, - 0xA3, 0xF0, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x51, - 0x7F, 0xFF, 0xFE, 0x12, 0x2B, 0x27, 0xBF, 0x01, - 0x09, 0x90, 0x81, 0x51, 0xE0, 0x64, 0x03, 0x60, - 0x03, 0x22, 0x01, 0xAB, 0xE4, 0x90, 0x81, 0x56, - 0xF0, 0x90, 0x81, 0x56, 0xE0, 0xFF, 0xC3, 0x94, - 0x02, 0x40, 0x02, 0x01, 0xE6, 0xC3, 0x74, 0xFE, - 0x9F, 0xFF, 0xE4, 0x94, 0x00, 0xFE, 0x7B, 0x01, - 0x7A, 0x81, 0x79, 0x52, 0x12, 0x2B, 0x27, 0xEF, - 0x64, 0x01, 0x70, 0x77, 0x90, 0x81, 0x52, 0xE0, - 0xFF, 0x54, 0xC0, 0xFE, 0x60, 0x05, 0xEF, 0x54, - 0x0C, 0x70, 0x16, 0x90, 0x81, 0x52, 0xE0, 0xFF, - 0x54, 0x30, 0x60, 0x67, 0xEF, 0x54, 0x03, 0x60, - 0x62, 0x90, 0x81, 0x53, 0x74, 0x01, 0xF0, 0x80, - 0x05, 0xE4, 0x90, 0x81, 0x53, 0xF0, 0x90, 0x81, - 0x53, 0xE0, 0x90, 0x81, 0x52, 0x70, 0x16, 0xE0, - 0xFF, 0xEE, 0x13, 0x13, 0x54, 0x3F, 0x90, 0x81, - 0x54, 0xF0, 0xEF, 0x54, 0x0C, 0x13, 0x13, 0x54, - 0x3F, 0xA3, 0xF0, 0x80, 0x0D, 0xE0, 0xFE, 0x54, - 0x30, 0x90, 0x81, 0x54, 0xF0, 0xEE, 0x54, 0x03, - 0xA3, 0xF0, 0x90, 0x81, 0x54, 0xE0, 0x64, 0x30, - 0x70, 0x54, 0xA3, 0xE0, 0x64, 0x02, 0x70, 0x4E, - 0x90, 0x00, 0xF5, 0xE0, 0x54, 0x40, 0x90, 0x81, - 0x57, 0xF0, 0xE0, 0x70, 0x41, 0xA3, 0x74, 0x02, - 0xF0, 0x80, 0x10, 0x90, 0x81, 0x58, 0x74, 0x01, - 0xF0, 0x80, 0x08, 0x90, 0x81, 0x56, 0xE0, 0x04, - 0xF0, 0x01, 0x11, 0x90, 0x01, 0xC4, 0x74, 0xE9, - 0xF0, 0x74, 0x57, 0xA3, 0xF0, 0x90, 0x81, 0x58, - 0xE0, 0x90, 0x01, 0xC8, 0xF0, 0x90, 0x81, 0x52, - 0xE0, 0x90, 0x01, 0xC9, 0xF0, 0x90, 0x81, 0x53, - 0xE0, 0x90, 0x01, 0xCA, 0xF0, 0xE4, 0xFD, 0x7F, - 0x1F, 0x12, 0x32, 0x1E, 0x80, 0xD5, 0x22, 0x90, - 0x00, 0xF7, 0xE0, 0x20, 0xE7, 0x09, 0xE0, 0x7F, - 0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90, - 0x00, 0xF7, 0xE0, 0x30, 0xE6, 0x02, 0x7F, 0x03, - 0x22, 0x11, 0xE7, 0x90, 0x80, 0x3C, 0xEF, 0xF0, - 0x31, 0x13, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0, - 0x02, 0x2D, 0xA7, 0x31, 0x81, 0x31, 0xB1, 0x31, - 0x40, 0x31, 0x5F, 0xE4, 0xF5, 0x35, 0xF5, 0x36, - 0xF5, 0x37, 0xF5, 0x38, 0xAD, 0x35, 0x7F, 0x50, - 0x12, 0x32, 0x1E, 0xAD, 0x36, 0x7F, 0x51, 0x12, - 0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32, - 0x1E, 0xAD, 0x38, 0x7F, 0x53, 0x02, 0x32, 0x1E, - 0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, 0x3F, - 0x07, 0x75, 0x40, 0x02, 0x90, 0x01, 0x30, 0xE5, - 0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, 0xE5, - 0x3F, 0xF0, 0xA3, 0xE5, 0x40, 0xF0, 0x22, 0x75, - 0x45, 0x0E, 0x75, 0x46, 0x01, 0x43, 0x46, 0x10, - 0x75, 0x47, 0x03, 0x75, 0x48, 0x62, 0x90, 0x01, - 0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0, - 0xA3, 0xE5, 0x47, 0xF0, 0xA3, 0xE5, 0x48, 0xF0, - 0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0, - 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x38, 0xF0, - 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, - 0x50, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x51, - 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12, - 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x53, 0x02, 0x32, - 0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3, - 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x3C, - 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, - 0x7F, 0x54, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, - 0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56, - 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x57, 0x02, - 0x32, 0x1E, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x80, - 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD, - 0x00, 0xE0, 0x54, 0xBF, 0xF0, 0x12, 0x57, 0xE9, - 0x51, 0x77, 0x12, 0x32, 0x77, 0x51, 0xC9, 0x51, - 0x5E, 0x7F, 0x01, 0x12, 0x43, 0x15, 0x90, 0x81, - 0x41, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x43, 0x15, - 0x90, 0x81, 0x41, 0xE0, 0x04, 0xF0, 0x7F, 0x03, - 0x12, 0x43, 0x15, 0x90, 0x81, 0x41, 0xE0, 0x04, - 0xF0, 0x31, 0x01, 0x51, 0x3F, 0x90, 0x00, 0x80, - 0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, 0x12, 0x32, - 0x1E, 0x75, 0x20, 0xFF, 0x51, 0x68, 0x51, 0xF9, - 0x51, 0x7F, 0xE4, 0xFF, 0x02, 0x43, 0x9E, 0x51, - 0x62, 0x51, 0x6F, 0x51, 0xA7, 0x71, 0x4F, 0x51, - 0x8A, 0x51, 0x95, 0x90, 0x81, 0x45, 0xE0, 0x54, - 0xFE, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xF0, - 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0xE4, 0xF5, - 0x4D, 0x22, 0xE4, 0x90, 0x80, 0xDE, 0xF0, 0x22, - 0x75, 0xE8, 0x03, 0x75, 0xA8, 0x84, 0x22, 0xE4, - 0x90, 0x80, 0xD8, 0xF0, 0xA3, 0xF0, 0x22, 0x90, - 0x01, 0x94, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, - 0x01, 0xE4, 0x74, 0x0B, 0xF0, 0xA3, 0x74, 0x01, - 0xF0, 0x22, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE, - 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x42, - 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, - 0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, - 0x81, 0x1F, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, - 0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, - 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0xE4, 0xA3, 0xF0, - 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0x74, 0x0C, 0xF0, - 0x22, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x04, 0xF0, - 0x90, 0x01, 0x9C, 0x74, 0x7E, 0xF0, 0xA3, 0x74, - 0x92, 0xF0, 0xA3, 0x74, 0xA0, 0xF0, 0xA3, 0x74, - 0x24, 0xF0, 0x90, 0x01, 0x9B, 0x74, 0x49, 0xF0, - 0x90, 0x01, 0x9A, 0x74, 0xE0, 0xF0, 0x90, 0x01, - 0x99, 0xE4, 0xF0, 0x90, 0x01, 0x98, 0x04, 0xF0, - 0x22, 0xE4, 0x90, 0x81, 0x51, 0xF0, 0xA3, 0xF0, - 0x90, 0x01, 0x98, 0xE0, 0x7F, 0x00, 0x30, 0xE4, - 0x02, 0x7F, 0x01, 0xEF, 0x64, 0x01, 0x60, 0x3E, - 0xC3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x88, 0x90, - 0x81, 0x51, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, - 0x01, 0xC1, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, - 0x81, 0x51, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, - 0xA9, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA, - 0xD3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x32, 0x90, - 0x81, 0x51, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90, - 0x01, 0xC6, 0xE0, 0x30, 0xE3, 0xB2, 0x22, 0xE4, - 0x90, 0x81, 0x27, 0xF0, 0xA3, 0xF0, 0x90, 0x81, - 0x26, 0xE0, 0x54, 0x0F, 0xF0, 0x54, 0xF0, 0xF0, - 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFD, 0xF0, 0x54, - 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x2D, - 0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x24, - 0xE0, 0x54, 0xFB, 0xF0, 0xA3, 0xE0, 0x54, 0xFB, - 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, - 0x2F, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xE4, - 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, 0x81, - 0x2B, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFE, - 0xF0, 0x90, 0x81, 0x29, 0x74, 0x0C, 0xF0, 0x90, - 0x81, 0x24, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x81, - 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x24, 0xE0, - 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0, - 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, - 0xF0, 0x90, 0x81, 0x34, 0x12, 0x20, 0xDA, 0x00, - 0x00, 0x00, 0x00, 0x90, 0x80, 0x3C, 0xE0, 0xB4, - 0x01, 0x08, 0x90, 0x81, 0x31, 0x74, 0x99, 0xF0, - 0x80, 0x12, 0x90, 0x80, 0x3C, 0xE0, 0x90, 0x81, - 0x31, 0xB4, 0x03, 0x05, 0x74, 0x90, 0xF0, 0x80, - 0x03, 0x74, 0x40, 0xF0, 0x90, 0x81, 0x38, 0x74, - 0x01, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xA3, 0xE0, - 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, - 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0xFD, - 0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, - 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0, - 0xE4, 0xA3, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x59, - 0xF0, 0x90, 0x81, 0x59, 0xE0, 0x64, 0x01, 0xF0, - 0x24, 0x24, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5C, - 0xA3, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0xFF, 0x90, - 0x81, 0x29, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x47, - 0x2A, 0xD1, 0x08, 0xBF, 0x01, 0x02, 0x91, 0x5F, - 0xB1, 0xF2, 0x12, 0x32, 0x9E, 0xBF, 0x01, 0x02, - 0xB1, 0x67, 0x12, 0x42, 0x4D, 0x80, 0xCA, 0xD3, - 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, - 0x24, 0xE0, 0x30, 0xE0, 0x24, 0x90, 0x81, 0x1F, - 0xE0, 0xFF, 0x30, 0xE0, 0x1A, 0xC3, 0x13, 0x30, - 0xE0, 0x07, 0xB1, 0xFB, 0xBF, 0x01, 0x12, 0x80, - 0x0A, 0x90, 0x81, 0x23, 0xE0, 0xFF, 0x60, 0x03, - 0xB4, 0x08, 0x06, 0x91, 0x96, 0x80, 0x02, 0x91, - 0xA6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, - 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xB1, 0x22, 0x91, - 0xBA, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, - 0x2A, 0xE0, 0x70, 0x0D, 0xD1, 0x2F, 0xBF, 0x01, - 0x08, 0x91, 0x96, 0x90, 0x01, 0xE5, 0xE0, 0x04, - 0xF0, 0x22, 0xB1, 0xF3, 0x90, 0x00, 0x08, 0xE0, - 0x54, 0xEF, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, - 0xE4, 0xFF, 0x8F, 0x50, 0xE4, 0x90, 0x81, 0x5A, - 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x09, 0xE0, 0x7F, - 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0xEF, 0x65, - 0x50, 0x60, 0x3E, 0xC3, 0x90, 0x81, 0x5B, 0xE0, - 0x94, 0x88, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x13, - 0x40, 0x08, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x10, - 0xF0, 0x22, 0x90, 0x81, 0x5A, 0xE4, 0x75, 0xF0, - 0x01, 0x12, 0x44, 0xA9, 0x7F, 0x14, 0x7E, 0x00, - 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x5B, 0xE0, - 0x94, 0x32, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x00, - 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE0, - 0xB2, 0x22, 0x90, 0x81, 0x31, 0xE0, 0xFD, 0x7F, - 0x93, 0x12, 0x32, 0x1E, 0x90, 0x81, 0x28, 0xE0, - 0x60, 0x12, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, - 0x05, 0x74, 0x10, 0xF0, 0x80, 0x06, 0x90, 0x01, - 0x2F, 0x74, 0x90, 0xF0, 0x90, 0x00, 0x08, 0xE0, - 0x44, 0x10, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, - 0x7F, 0x01, 0x91, 0xCA, 0x90, 0x00, 0x90, 0xE0, - 0x44, 0x01, 0xFD, 0x7F, 0x90, 0x12, 0x32, 0x1E, - 0x7F, 0x14, 0x7E, 0x00, 0x02, 0x32, 0xAA, 0xD3, - 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x2D, - 0xA7, 0xE4, 0xF5, 0x52, 0x12, 0x32, 0x9E, 0xEF, - 0x60, 0x73, 0x63, 0x52, 0x01, 0xE5, 0x52, 0x24, - 0x67, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5D, 0xA3, - 0xF0, 0x90, 0x00, 0x88, 0xE0, 0xF5, 0x50, 0xF5, - 0x51, 0x54, 0x0F, 0x60, 0xDF, 0xE5, 0x50, 0x30, - 0xE0, 0x0B, 0x20, 0xE4, 0x03, 0x12, 0x29, 0xC5, - 0x53, 0x51, 0xEE, 0x80, 0x3F, 0xE5, 0x50, 0x30, - 0xE1, 0x16, 0x20, 0xE5, 0x0E, 0x12, 0x11, 0xBD, - 0xEF, 0x70, 0x03, 0x43, 0x51, 0x20, 0x90, 0x01, - 0x06, 0xE4, 0xF0, 0x53, 0x51, 0xFD, 0x80, 0x24, - 0xE5, 0x50, 0x30, 0xE2, 0x0B, 0x20, 0xE6, 0x03, - 0x12, 0x67, 0x06, 0x53, 0x51, 0xFB, 0x80, 0x14, - 0xE5, 0x50, 0x30, 0xE3, 0x0F, 0x20, 0xE7, 0x09, - 0x12, 0x61, 0x6E, 0xEF, 0x70, 0x03, 0x43, 0x51, - 0x80, 0x53, 0x51, 0xF7, 0xAD, 0x51, 0x7F, 0x88, - 0x12, 0x32, 0x1E, 0x80, 0x87, 0xD0, 0xD0, 0x92, - 0xAF, 0x22, 0x22, 0x90, 0x00, 0x90, 0xE0, 0x20, - 0xE0, 0xF9, 0x22, 0x90, 0x81, 0x22, 0xE0, 0x64, - 0x02, 0x7F, 0x01, 0x60, 0x02, 0x7F, 0x00, 0x22, - 0x7F, 0x02, 0x90, 0x81, 0x41, 0xE0, 0xFE, 0xEF, - 0xC3, 0x9E, 0x50, 0x18, 0xEF, 0x25, 0xE0, 0x24, - 0x81, 0xF8, 0xE6, 0x30, 0xE4, 0x0B, 0x90, 0x01, - 0xB8, 0x74, 0x08, 0xF0, 0xA3, 0xF0, 0x7F, 0x00, - 0x22, 0x0F, 0x80, 0xDE, 0x7F, 0x01, 0x22, 0x90, - 0x02, 0x87, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, - 0x74, 0x01, 0xF0, 0x80, 0x17, 0x90, 0x02, 0x86, - 0xE0, 0x20, 0xE1, 0x08, 0x90, 0x01, 0xB8, 0x74, - 0x04, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, - 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, - 0x08, 0xF0, 0x7F, 0x00, 0x22, 0xE4, 0xFB, 0xFA, - 0xFD, 0x7F, 0x01, 0x12, 0x44, 0x4E, 0x90, 0x81, - 0xBD, 0xEF, 0xF0, 0x60, 0xF0, 0xD1, 0x71, 0x80, - 0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, - 0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x81, - 0xBE, 0xF0, 0x90, 0x81, 0xBE, 0xE0, 0xFD, 0x70, - 0x02, 0xE1, 0x9C, 0x90, 0x82, 0x09, 0xE0, 0xFF, - 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, - 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, - 0xFF, 0xEF, 0x5D, 0x70, 0x02, 0xE1, 0x95, 0x90, - 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, - 0xD0, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xBF, - 0xF0, 0x75, 0x13, 0x01, 0x75, 0x14, 0x81, 0x75, - 0x15, 0xBF, 0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A, - 0x81, 0x79, 0xC0, 0x12, 0x2B, 0xED, 0x90, 0x82, - 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD1, - 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC1, 0xF0, - 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, - 0x01, 0xD2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, - 0xC2, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, - 0x04, 0x90, 0x01, 0xD3, 0x12, 0x45, 0x0A, 0xE0, - 0x90, 0x81, 0xC3, 0xF0, 0x90, 0x82, 0x09, 0xE0, - 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF0, 0x12, 0x45, - 0x0A, 0xE0, 0x90, 0x81, 0xC4, 0xF0, 0x90, 0x82, - 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF1, - 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC5, 0xF0, - 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, - 0x01, 0xF2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, - 0xC6, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, - 0x04, 0x90, 0x01, 0xF3, 0x12, 0x45, 0x0A, 0xE0, - 0x90, 0x81, 0xC7, 0xF0, 0x90, 0x81, 0xBE, 0xE0, - 0xFF, 0x90, 0x82, 0x09, 0xE0, 0xFE, 0x74, 0x01, - 0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, - 0xFC, 0xF4, 0x5F, 0x90, 0x81, 0xBE, 0xF0, 0x90, - 0x82, 0x09, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, - 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90, - 0x01, 0xCC, 0xF0, 0x90, 0x81, 0xC0, 0xE0, 0xFF, - 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC1, 0x12, 0x55, - 0x3F, 0x90, 0x82, 0x09, 0xE0, 0x04, 0xF0, 0xE0, - 0x54, 0x03, 0xF0, 0xC1, 0x82, 0x90, 0x01, 0xC0, - 0xE0, 0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, - 0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, - 0x44, 0x4E, 0x90, 0x81, 0xD0, 0xEF, 0xF0, 0x60, - 0xF0, 0x12, 0x6C, 0x19, 0x80, 0xEB, 0x90, 0x81, - 0xD4, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, 0x12, - 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x90, - 0x81, 0xE2, 0xF0, 0x7F, 0x24, 0x7E, 0x08, 0x12, - 0x2D, 0x5C, 0x90, 0x81, 0xDA, 0x12, 0x20, 0xCE, - 0x90, 0x81, 0xD4, 0xE0, 0xFB, 0x70, 0x08, 0x90, - 0x81, 0xDA, 0x12, 0x44, 0xD9, 0x80, 0x16, 0xEB, - 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, - 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, - 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x81, 0xDE, - 0x12, 0x20, 0xCE, 0x90, 0x81, 0xD5, 0xE0, 0xFF, - 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, 0x20, - 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, - 0x07, 0x90, 0x81, 0xDE, 0x12, 0x44, 0xD9, 0xED, - 0x54, 0x7F, 0xFD, 0xEC, 0x54, 0x80, 0xFC, 0x12, - 0x44, 0xCC, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x81, - 0xDE, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xDA, 0x12, - 0x44, 0xD9, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x85, - 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, - 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xD4, 0xE0, 0x75, - 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4, - 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, - 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xDE, - 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, - 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x12, 0x2E, 0xA2, - 0x90, 0x81, 0xDA, 0x12, 0x44, 0xD9, 0xEC, 0x44, - 0x80, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, - 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, - 0x81, 0xD4, 0xE0, 0x70, 0x04, 0x7F, 0x20, 0x80, - 0x09, 0x90, 0x81, 0xD4, 0xE0, 0xB4, 0x01, 0x16, - 0x7F, 0x28, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x78, - 0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, 0xFF, - 0xE4, 0x90, 0x81, 0xE2, 0xEF, 0xF0, 0x90, 0x81, - 0xE2, 0xE0, 0x90, 0x81, 0xD4, 0x60, 0x0E, 0xE0, - 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x66, 0xF5, 0x82, - 0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, 0xF0, - 0x08, 0xA4, 0x24, 0x64, 0xF5, 0x82, 0xE4, 0x34, - 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, - 0x12, 0x2D, 0x5C, 0xED, 0x54, 0x0F, 0xFD, 0xE4, - 0xFC, 0x90, 0x81, 0xD6, 0x12, 0x20, 0xCE, 0x90, - 0x81, 0xD6, 0x02, 0x44, 0xD9, 0x90, 0x81, 0xE3, - 0xEF, 0xF0, 0xAB, 0x05, 0x90, 0x81, 0xE9, 0x12, - 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x03, - 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, 0x20, - 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, - 0x07, 0x90, 0x81, 0xE5, 0x12, 0x44, 0xD9, 0xED, - 0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x12, 0x44, 0xCC, - 0xEC, 0x54, 0x0F, 0xFC, 0x90, 0x81, 0xE9, 0x12, - 0x20, 0xCE, 0x90, 0x81, 0xE3, 0xE0, 0x75, 0xF0, - 0x08, 0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, 0x34, - 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, - 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xE9, 0x12, - 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, - 0xD0, 0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, 0xD3, - 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x5F, - 0xB6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x78, 0x10, - 0x74, 0x01, 0xF2, 0x90, 0x02, 0x09, 0xE0, 0x78, - 0x00, 0xF2, 0x08, 0x74, 0x20, 0xF2, 0x18, 0xE2, - 0xFF, 0x30, 0xE0, 0x05, 0x08, 0xE2, 0x24, 0x80, - 0xF2, 0xEF, 0xC3, 0x13, 0x90, 0xFD, 0x10, 0xF0, - 0x78, 0x01, 0xE2, 0x24, 0x00, 0xF5, 0x82, 0xE4, - 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x78, 0x03, 0xF2, - 0x64, 0x04, 0x60, 0x0D, 0xE2, 0xFF, 0x64, 0x08, - 0x60, 0x07, 0xEF, 0x64, 0x0C, 0x60, 0x02, 0x61, - 0xDE, 0xE4, 0x78, 0x02, 0xF2, 0x78, 0x03, 0xE2, - 0xFF, 0x18, 0xE2, 0xC3, 0x9F, 0x50, 0x2D, 0xE2, - 0xFD, 0x18, 0xE2, 0x2D, 0x90, 0x81, 0x5A, 0xF0, - 0xE0, 0xFF, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, - 0xFC, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x04, 0x2D, - 0xF8, 0xEE, 0xF2, 0xEF, 0xB4, 0xFF, 0x06, 0x90, - 0xFD, 0x10, 0xE0, 0x04, 0xF0, 0x78, 0x02, 0xE2, - 0x04, 0xF2, 0x80, 0xC9, 0x78, 0x04, 0xE2, 0x78, - 0x12, 0xF2, 0xFF, 0x78, 0x05, 0xE2, 0x78, 0x11, - 0xF2, 0x78, 0x06, 0xE2, 0x78, 0x13, 0xF2, 0x78, - 0x07, 0xE2, 0x78, 0x14, 0xF2, 0x78, 0x08, 0xE2, - 0x78, 0x33, 0xF2, 0x78, 0x09, 0xE2, 0x78, 0x34, - 0xF2, 0x78, 0x0A, 0xE2, 0x78, 0x35, 0xF2, 0x78, - 0x0B, 0xE2, 0x78, 0x36, 0xF2, 0x78, 0x0C, 0xE2, - 0x78, 0x37, 0xF2, 0x78, 0x0D, 0xE2, 0x78, 0x38, - 0xF2, 0x78, 0x0E, 0xE2, 0x78, 0x39, 0xF2, 0x78, - 0x0F, 0xE2, 0x78, 0x3A, 0xF2, 0xE4, 0x78, 0x15, - 0xF2, 0xEF, 0x24, 0xF8, 0x60, 0x75, 0x24, 0xFC, - 0x60, 0x6C, 0x24, 0x08, 0x60, 0x02, 0x61, 0xC0, - 0x78, 0x11, 0xE2, 0xB4, 0x01, 0x05, 0x12, 0x29, - 0xC5, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x02, - 0x05, 0x12, 0x11, 0xBD, 0x61, 0xC5, 0x78, 0x11, - 0xE2, 0xB4, 0x03, 0x04, 0xF1, 0x06, 0x61, 0xC5, - 0x78, 0x11, 0xE2, 0xB4, 0x10, 0x17, 0x78, 0x14, - 0xE2, 0xFE, 0x18, 0xE2, 0xFD, 0xED, 0xFF, 0x78, - 0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF, - 0x12, 0x32, 0xAA, 0x61, 0xC5, 0x78, 0x11, 0xE2, - 0xB4, 0x11, 0x17, 0x78, 0x14, 0xE2, 0xFE, 0x18, - 0xE2, 0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2, - 0xFE, 0x08, 0xEF, 0xF2, 0xFF, 0x12, 0x32, 0x06, - 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xF4, 0x60, 0x02, - 0x61, 0xC5, 0x18, 0xF2, 0x61, 0xC5, 0x78, 0x15, - 0x74, 0x01, 0xF2, 0x78, 0x11, 0xE2, 0x64, 0x07, - 0x60, 0x02, 0x61, 0xAA, 0x78, 0x34, 0xE2, 0xFF, - 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, - 0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, - 0x07, 0x78, 0x33, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, - 0xFE, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0xC0, 0x04, - 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x35, - 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, - 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, - 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18, - 0x12, 0x44, 0xFE, 0x78, 0x15, 0xE2, 0x70, 0x02, - 0x61, 0x93, 0x18, 0xE2, 0xFF, 0x18, 0xE2, 0xFD, - 0x31, 0x5F, 0x78, 0x1C, 0x12, 0x44, 0xFE, 0x78, - 0x38, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, - 0x08, 0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05, - 0xAA, 0x06, 0xAB, 0x07, 0x78, 0x37, 0xE2, 0xFF, - 0xE4, 0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x44, - 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, - 0x07, 0x78, 0x39, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, - 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03, - 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, - 0xCC, 0x78, 0x20, 0x12, 0x44, 0xFE, 0x78, 0x20, - 0x12, 0x44, 0xE5, 0x12, 0x20, 0x9B, 0x78, 0x1C, - 0x12, 0x44, 0xF1, 0x12, 0x44, 0xBF, 0xC0, 0x04, - 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x18, - 0x12, 0x44, 0xE5, 0x78, 0x20, 0x12, 0x44, 0xF1, - 0x12, 0x44, 0xBF, 0xD0, 0x03, 0xD0, 0x02, 0xD0, - 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18, - 0x12, 0x44, 0xFE, 0x78, 0x18, 0x12, 0x44, 0xE5, - 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x78, 0x13, - 0xE2, 0xFD, 0x08, 0xE2, 0xFF, 0x12, 0x55, 0x1C, - 0x80, 0x1B, 0x78, 0x13, 0xE2, 0xFF, 0x08, 0xE2, - 0xFD, 0x78, 0x11, 0xE2, 0xFB, 0x78, 0x15, 0xE2, - 0x90, 0x81, 0xBC, 0xF0, 0x71, 0xE1, 0x80, 0x05, - 0x78, 0x10, 0x74, 0x02, 0xF2, 0x78, 0x10, 0xE2, - 0xFF, 0xC3, 0x94, 0x02, 0x50, 0x10, 0xEF, 0x60, - 0x0A, 0x78, 0x02, 0xE2, 0xFF, 0x18, 0xE2, 0x2F, - 0xF2, 0x21, 0x90, 0x7F, 0x01, 0x22, 0x7F, 0x00, - 0x22, 0xAC, 0x07, 0xED, 0xAD, 0x04, 0x78, 0x24, - 0xF2, 0xED, 0x08, 0xF2, 0xEB, 0xB4, 0x04, 0x07, - 0x78, 0x27, 0x74, 0x01, 0xF2, 0x80, 0x0E, 0xEB, - 0x78, 0x27, 0xB4, 0x05, 0x05, 0x74, 0x02, 0xF2, - 0x80, 0x03, 0x74, 0x04, 0xF2, 0xD3, 0x78, 0x25, - 0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x00, 0x50, - 0x63, 0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, - 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, - 0xA1, 0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, - 0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D, - 0x74, 0x37, 0x2E, 0xF8, 0xE2, 0x78, 0x32, 0xF2, - 0xEE, 0xFF, 0x78, 0x25, 0xE2, 0x2F, 0xFF, 0x18, - 0xE2, 0x34, 0x00, 0x8F, 0x82, 0xF5, 0x83, 0xE0, - 0x78, 0x29, 0xF2, 0x78, 0x32, 0xE2, 0xFF, 0xF4, - 0xFE, 0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, - 0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x24, 0x08, - 0xE2, 0xFF, 0x08, 0xE2, 0x2F, 0xFF, 0x78, 0x28, - 0xE2, 0xFD, 0x12, 0x32, 0x1E, 0x78, 0x26, 0xE2, - 0x04, 0xF2, 0x80, 0xA1, 0xD3, 0x78, 0x25, 0xE2, - 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x07, 0x50, 0x69, - 0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, - 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, 0xA1, - 0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28, - 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D, 0x78, - 0x26, 0xE2, 0xFF, 0xFD, 0x18, 0xE2, 0x2D, 0xFD, - 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83, - 0xE0, 0x78, 0x29, 0xF2, 0x74, 0x37, 0x2F, 0xF8, - 0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFF, 0xF4, 0xFE, - 0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD, - 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x28, 0xE2, 0xFF, - 0x78, 0x26, 0xE2, 0xFD, 0x18, 0xE2, 0x2D, 0xFD, - 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83, - 0xEF, 0xF0, 0x78, 0x26, 0xE2, 0x04, 0xF2, 0x80, - 0x9B, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x0F, 0x78, - 0x24, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2D, - 0x5C, 0x78, 0x2E, 0x12, 0x44, 0xFE, 0xE4, 0x78, - 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, - 0xFE, 0xC3, 0x9F, 0x50, 0x5D, 0x74, 0x33, 0x2E, - 0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC, - 0xE0, 0x60, 0x2B, 0x78, 0x2E, 0x12, 0x44, 0xE5, - 0x78, 0x26, 0xE2, 0xFB, 0x75, 0xF0, 0x08, 0xA4, - 0xF9, 0xF8, 0x12, 0x20, 0xA8, 0x78, 0x29, 0xEF, - 0xF2, 0x74, 0x37, 0x2B, 0xF8, 0xE2, 0x78, 0x32, - 0xF2, 0xE2, 0xFE, 0xF4, 0x5F, 0xFF, 0x78, 0x28, - 0xE2, 0xFD, 0xEE, 0x5D, 0x4F, 0xF2, 0x78, 0x28, - 0xE2, 0xFF, 0x78, 0x26, 0xE2, 0xFD, 0xC3, 0x74, - 0x03, 0x9D, 0xFD, 0xE4, 0x94, 0x00, 0xFC, 0x7B, - 0xFE, 0x74, 0x2A, 0x2D, 0xF9, 0x74, 0x80, 0x3C, - 0xFA, 0xEF, 0x12, 0x1F, 0xEA, 0xE2, 0x04, 0xF2, - 0x80, 0x98, 0x78, 0x2A, 0x12, 0x44, 0xE5, 0x90, - 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x78, 0x24, 0xE2, - 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2E, 0xA2, 0x22, - 0x22, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x90, - 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xFE, 0x12, - 0x1F, 0xA4, 0xFD, 0xC3, 0x13, 0x30, 0xE0, 0x12, - 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00, - 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0xCF, 0xF0, - 0x80, 0x05, 0x90, 0x81, 0xCF, 0xEF, 0xF0, 0x90, - 0x81, 0xCE, 0xEE, 0xF0, 0x90, 0x81, 0xCF, 0xE0, - 0xFE, 0x90, 0x81, 0xCE, 0xE0, 0xFF, 0xD3, 0x9E, - 0x50, 0x38, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, - 0x12, 0x1F, 0xA4, 0x54, 0x01, 0xFE, 0x74, 0xDE, - 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, - 0xEE, 0xF0, 0x74, 0xDE, 0x2F, 0xF5, 0x82, 0xE4, - 0x34, 0x80, 0xF5, 0x83, 0xE0, 0x70, 0x04, 0xD1, - 0x25, 0x80, 0x07, 0x90, 0x81, 0xCE, 0xE0, 0xFF, - 0xB1, 0x80, 0x90, 0x81, 0xCE, 0xE0, 0x04, 0xF0, - 0x80, 0xBA, 0x90, 0x80, 0xDE, 0xE0, 0x70, 0x24, - 0x90, 0x81, 0x2A, 0xE0, 0x70, 0x04, 0xFF, 0x12, - 0x49, 0x93, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C, - 0x60, 0x02, 0xD1, 0x26, 0x90, 0x81, 0x24, 0xE0, - 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xBF, - 0xF0, 0x54, 0x7F, 0xF0, 0x22, 0x22, 0x90, 0x06, - 0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x05, 0x22, - 0xE4, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, - 0x22, 0x90, 0x81, 0xED, 0xEF, 0xF0, 0xA3, 0xED, - 0xF0, 0xAD, 0x03, 0xAC, 0x02, 0xE4, 0x90, 0x81, - 0xF5, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0xC4, 0x74, - 0x39, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0xEC, 0x54, - 0x3F, 0xFC, 0x90, 0x01, 0x40, 0xED, 0xF0, 0xAE, - 0x04, 0xEE, 0xA3, 0xF0, 0x90, 0x81, 0xED, 0xE0, - 0x24, 0x81, 0x60, 0x34, 0x24, 0xDA, 0x60, 0x1C, - 0x24, 0x3C, 0x70, 0x41, 0x90, 0x81, 0xEE, 0xE0, - 0xC4, 0x33, 0x33, 0x33, 0x54, 0x80, 0x90, 0x81, - 0xF2, 0xF0, 0xA3, 0x74, 0x69, 0xF0, 0xA3, 0x74, - 0x80, 0xF0, 0x80, 0x2C, 0x90, 0x81, 0xEE, 0xE0, - 0x54, 0x01, 0x90, 0x81, 0xF2, 0xF0, 0xA3, 0x74, - 0xA5, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x80, 0x18, - 0x90, 0x81, 0xEE, 0xE0, 0xC4, 0x54, 0x10, 0x90, - 0x81, 0xF2, 0xF0, 0xA3, 0x74, 0x7F, 0xF0, 0xA3, - 0x74, 0x10, 0xF0, 0x80, 0x03, 0x7F, 0x00, 0x22, - 0x90, 0x81, 0xF3, 0xE0, 0x90, 0x01, 0x06, 0xF0, - 0x90, 0x81, 0xF2, 0xE0, 0x60, 0x0E, 0x90, 0x01, - 0x42, 0xF0, 0x90, 0x81, 0xF1, 0xE0, 0x90, 0x01, - 0x43, 0xF0, 0x80, 0x0D, 0x90, 0x01, 0x43, 0xE4, - 0xF0, 0x90, 0x81, 0xF2, 0xE0, 0x90, 0x01, 0x42, - 0xF0, 0x90, 0x81, 0xF4, 0xE0, 0xFF, 0x90, 0x01, - 0x42, 0xE0, 0x5F, 0xFF, 0x90, 0x81, 0xF2, 0xE0, - 0x6F, 0x60, 0xEE, 0x74, 0x39, 0x04, 0x90, 0x01, - 0xC4, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0x90, 0x01, - 0x43, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0xE4, 0x90, - 0x81, 0x6A, 0xF0, 0x90, 0x87, 0x5F, 0xE0, 0x90, - 0x81, 0x69, 0xF0, 0xE4, 0x90, 0x81, 0x76, 0xF0, - 0x90, 0x81, 0x66, 0xF0, 0x90, 0x81, 0x66, 0xE0, - 0xFF, 0xC3, 0x94, 0x40, 0x50, 0x15, 0x74, 0x79, - 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, - 0x74, 0xFF, 0xF0, 0x90, 0x81, 0x66, 0xE0, 0x04, - 0xF0, 0x80, 0xE1, 0xE4, 0x90, 0x81, 0x66, 0xF0, - 0x90, 0x81, 0x69, 0xE0, 0xFF, 0x90, 0x81, 0x66, - 0xE0, 0xFE, 0xC3, 0x9F, 0x40, 0x03, 0x02, 0x68, - 0x12, 0x74, 0xDF, 0x2E, 0xF9, 0xE4, 0x34, 0x86, - 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, - 0x16, 0x0A, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x5B, - 0x12, 0x2B, 0xED, 0x90, 0x81, 0x5C, 0xE0, 0xFF, - 0x12, 0x2F, 0x27, 0xEF, 0x04, 0x90, 0x81, 0x76, - 0xF0, 0x90, 0x81, 0x5B, 0xE0, 0xFF, 0xA3, 0xE0, - 0xFD, 0x12, 0x31, 0xEA, 0xEF, 0x24, 0xC8, 0x90, - 0x81, 0x78, 0xF0, 0x75, 0xF0, 0x08, 0xA4, 0xF0, - 0x90, 0x81, 0x5C, 0xE0, 0x54, 0x0F, 0x90, 0x81, - 0x77, 0xF0, 0xE4, 0x90, 0x81, 0x65, 0xF0, 0x90, - 0x81, 0x67, 0xF0, 0x90, 0x81, 0x67, 0xE0, 0xFF, - 0xC3, 0x94, 0x04, 0x50, 0x57, 0x90, 0x81, 0x77, - 0xE0, 0xFE, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, - 0x13, 0xD8, 0xFC, 0x20, 0xE0, 0x3E, 0x90, 0x81, - 0x67, 0xE0, 0x25, 0xE0, 0xFF, 0x90, 0x81, 0x78, - 0xE0, 0x2F, 0x24, 0x79, 0xF9, 0xE4, 0x34, 0x81, - 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x01, 0x90, - 0x81, 0x65, 0xE0, 0x75, 0xF0, 0x02, 0xA4, 0x24, - 0x5D, 0xF9, 0x74, 0x81, 0x35, 0xF0, 0x8B, 0x13, - 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x02, 0xD0, - 0x01, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x81, - 0x65, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x67, 0xE0, - 0x04, 0xF0, 0x80, 0x9F, 0x90, 0x81, 0x76, 0xE0, - 0xFF, 0x90, 0x81, 0x66, 0xE0, 0x2F, 0xF0, 0x02, - 0x67, 0x40, 0xE4, 0x90, 0x81, 0x6A, 0xF0, 0x90, - 0x81, 0x6A, 0xE0, 0xC3, 0x94, 0x40, 0x40, 0x02, - 0x41, 0xAF, 0xE0, 0xFF, 0x24, 0x79, 0xF5, 0x82, - 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, 0x81, - 0x6C, 0xF0, 0xE0, 0xFE, 0x54, 0xF0, 0xC4, 0x54, - 0x0F, 0xFD, 0x90, 0x81, 0x6B, 0xF0, 0xEE, 0x54, - 0x0F, 0xFE, 0xA3, 0xF0, 0x74, 0x7A, 0x2F, 0xF5, - 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, - 0x81, 0x6D, 0xF0, 0xFC, 0xEE, 0xFE, 0xEC, 0xFB, - 0xEB, 0xFF, 0x90, 0x81, 0x72, 0xEE, 0xF0, 0xA3, - 0xEF, 0xF0, 0xED, 0x12, 0x45, 0x28, 0x68, 0x8B, - 0x00, 0x68, 0xC2, 0x01, 0x69, 0x73, 0x02, 0x6A, - 0xA0, 0x03, 0x69, 0x8E, 0x04, 0x69, 0xAF, 0x05, - 0x69, 0xAF, 0x06, 0x69, 0xAF, 0x07, 0x69, 0xAF, - 0x08, 0x6A, 0x33, 0x09, 0x6A, 0x69, 0x0A, 0x00, - 0x00, 0x6A, 0xAF, 0x90, 0x81, 0x6A, 0xE0, 0xFD, - 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, - 0x83, 0xE0, 0xFE, 0x74, 0x7B, 0x2D, 0xF5, 0x82, - 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFD, 0xED, - 0xFF, 0x90, 0x81, 0x74, 0xEE, 0xF0, 0xFC, 0xA3, - 0xEF, 0xF0, 0x90, 0x81, 0x6D, 0xE0, 0xFF, 0x12, - 0x2F, 0x96, 0x90, 0x81, 0x68, 0x74, 0x02, 0xF0, - 0x41, 0xA0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7C, - 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, - 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, - 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, - 0xAB, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, - 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, - 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, 0x44, 0xCC, - 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, - 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7D, 0xF5, 0x82, - 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, - 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, - 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, - 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, - 0x06, 0xC0, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, - 0x7E, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, - 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x18, - 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, - 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81, - 0x6E, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x6E, 0x12, - 0x44, 0xD9, 0x90, 0x85, 0x96, 0x12, 0x20, 0xCE, - 0x90, 0x81, 0x72, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, - 0x12, 0x2E, 0xE4, 0x90, 0x81, 0x68, 0x74, 0x04, - 0xF0, 0x41, 0xA0, 0x90, 0x81, 0x6D, 0xE0, 0xFD, - 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, - 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, - 0xFF, 0x12, 0x30, 0xC7, 0x80, 0x19, 0x90, 0x81, - 0x6D, 0xE0, 0xFD, 0x90, 0x81, 0x6A, 0xE0, 0x24, - 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, - 0xE0, 0xFB, 0xE4, 0xFF, 0x12, 0x30, 0x6A, 0x90, - 0x81, 0x68, 0x74, 0x01, 0xF0, 0x41, 0xA0, 0x90, - 0x81, 0x68, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x6A, - 0xE0, 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, - 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, - 0x78, 0x08, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, - 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0x6A, - 0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, - 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, - 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, - 0x06, 0xC0, 0x07, 0x90, 0x81, 0x6C, 0xE0, 0xFF, - 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, - 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, - 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81, 0x6E, 0x12, - 0x20, 0xCE, 0x90, 0x81, 0x6B, 0xE0, 0x24, 0xFB, - 0xFF, 0xC0, 0x07, 0x90, 0x81, 0x6E, 0x12, 0x44, - 0xD9, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x90, - 0x81, 0x6D, 0xE0, 0xFD, 0xD0, 0x07, 0x12, 0x55, - 0x1C, 0x80, 0x6D, 0x90, 0x81, 0x68, 0x74, 0x01, - 0xF0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9, - 0xE4, 0x34, 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, - 0x89, 0x15, 0x75, 0x16, 0x01, 0x7B, 0xFE, 0x7A, - 0x80, 0x79, 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, - 0x6D, 0xE0, 0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD, - 0xE4, 0x90, 0x81, 0xBC, 0xF0, 0x7B, 0x04, 0x80, - 0x34, 0x90, 0x81, 0x68, 0x74, 0x04, 0xF0, 0x90, - 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9, 0xE4, 0x34, - 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, - 0x75, 0x16, 0x04, 0x7B, 0xFE, 0x7A, 0x80, 0x79, - 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x6D, 0xE0, - 0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD, 0xE4, 0x90, - 0x81, 0xBC, 0xF0, 0x7B, 0x06, 0x12, 0x63, 0xE1, - 0x90, 0x81, 0x68, 0xE0, 0x24, 0x02, 0xFF, 0x90, - 0x81, 0x6A, 0xE0, 0x2F, 0xF0, 0x01, 0x17, 0x22, - 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, - 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x80, 0x3D, - 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, - 0xED, 0x2F, 0x90, 0x80, 0x3E, 0xF0, 0x90, 0x00, - 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, - 0x80, 0x3F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, - 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x40, 0xF0, - 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xAE, - 0x05, 0xED, 0x2F, 0x90, 0x80, 0x41, 0xF0, 0x22, - 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0x30, - 0xE0, 0x26, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x38, - 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, - 0x81, 0x39, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3, - 0xE0, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x00, 0x03, - 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x3B, 0xF0, 0x22, - 0x90, 0x81, 0x38, 0x74, 0x01, 0xF0, 0xA3, 0x74, - 0x05, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, - 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0x12, 0x1F, - 0xA4, 0x90, 0x81, 0x3E, 0xF0, 0x90, 0x81, 0x3E, - 0xE0, 0x90, 0x01, 0xE7, 0xF0, 0x22, 0x12, 0x1F, - 0xA4, 0x90, 0x81, 0x4A, 0xF0, 0x90, 0x00, 0x01, - 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x4B, 0xF0, 0x22, - 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, - 0x81, 0xFD, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4, - 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0xFD, 0xE0, - 0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0xE0, - 0x60, 0x2D, 0xC3, 0x90, 0x82, 0x00, 0xE0, 0x94, - 0xE8, 0x90, 0x81, 0xFF, 0xE0, 0x94, 0x03, 0x40, - 0x0B, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0, - 0x7F, 0x00, 0x80, 0x15, 0x90, 0x81, 0xFF, 0xE4, - 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x7F, 0x0A, - 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, 0x7F, - 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, - 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xD1, - 0x12, 0x45, 0x1F, 0x90, 0x82, 0x0A, 0xE0, 0xFF, - 0x04, 0xF0, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F, - 0xFC, 0x7F, 0xAF, 0x7E, 0x01, 0x71, 0x60, 0xEF, - 0x60, 0x3A, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16, - 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, 0x00, - 0x0E, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xF5, 0x16, - 0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B, - 0xED, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16, 0x90, - 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE, - 0xF0, 0xA3, 0x74, 0xFF, 0xF0, 0x90, 0x01, 0xCB, - 0xE0, 0x64, 0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, - 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, - 0xE4, 0xFF, 0x90, 0x80, 0xD9, 0xE0, 0xFE, 0x90, - 0x80, 0xD8, 0xE0, 0xFD, 0xB5, 0x06, 0x04, 0x7E, - 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x64, 0x01, - 0x60, 0x32, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x13, - 0xED, 0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x42, 0xF9, - 0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0x71, - 0xB6, 0x7F, 0x01, 0xEF, 0x60, 0x16, 0x90, 0x80, - 0xD8, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, - 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, - 0x90, 0x80, 0xD8, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, - 0x22, 0x8F, 0x0D, 0x22, 0x8F, 0x0E, 0x22, 0x22, - 0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41, - 0xA3, 0xE0, 0x55, 0x3E, 0xF5, 0x42, 0xA3, 0xE0, - 0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40, - 0xF5, 0x44, 0x90, 0x01, 0x34, 0xE5, 0x41, 0xF0, - 0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0, - 0xA3, 0xE5, 0x44, 0xF0, 0x22, 0x90, 0x01, 0x3C, - 0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55, - 0x46, 0xF5, 0x4A, 0xA3, 0xE0, 0x55, 0x47, 0xF5, - 0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90, - 0x01, 0x3C, 0xE5, 0x49, 0xF0, 0xA3, 0xE5, 0x4A, - 0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C, - 0xF0, 0x53, 0x91, 0xDF, 0x22, 0x90, 0x81, 0x1F, - 0xE0, 0x30, 0xE0, 0x05, 0xE4, 0xA3, 0xF0, 0xA3, - 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, - 0x70, 0x19, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x13, - 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, - 0x74, 0x02, 0x12, 0x4F, 0xF4, 0x90, 0x01, 0x57, - 0x74, 0x05, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, - 0x64, 0x01, 0x70, 0x26, 0x90, 0x81, 0x27, 0xE0, - 0x60, 0x20, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, - 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, - 0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, - 0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x03, 0x12, - 0x47, 0x2A, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0xB4, - 0x01, 0x14, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0E, - 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, - 0x60, 0x02, 0x80, 0x03, 0xD1, 0x7F, 0x22, 0x90, - 0x04, 0x1D, 0xE0, 0x70, 0x13, 0x90, 0x80, 0x3E, - 0xE0, 0xFF, 0xE4, 0xFD, 0xB1, 0x69, 0x8E, 0x4E, - 0x8F, 0x4F, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, - 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, - 0x90, 0x82, 0x0E, 0xED, 0xF0, 0x90, 0x82, 0x0D, - 0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0xF1, 0x37, 0x7C, - 0x00, 0xAD, 0x07, 0x90, 0x82, 0x0D, 0xE0, 0x90, - 0x04, 0x25, 0xF0, 0x90, 0x82, 0x0E, 0xE0, 0x60, - 0x0E, 0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, 0x34, - 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF, - 0x05, 0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, 0x34, - 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F, - 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, - 0x54, 0xF0, 0xF0, 0x74, 0x21, 0x2D, 0xF5, 0x82, - 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF7, - 0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92, - 0xAF, 0x22, 0x8F, 0x4E, 0xF1, 0x4B, 0xBF, 0x01, - 0x18, 0x90, 0x80, 0x40, 0xE0, 0xFF, 0x7D, 0x01, - 0xB1, 0x69, 0xAD, 0x07, 0xAC, 0x06, 0xAF, 0x4E, - 0x12, 0x4F, 0x82, 0x90, 0x04, 0x1F, 0x74, 0x20, - 0xF0, 0x22, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x81, - 0x4C, 0xF0, 0xE0, 0xFD, 0x54, 0xC0, 0x70, 0x09, - 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x80, - 0x72, 0xED, 0x30, 0xE6, 0x4B, 0x90, 0x81, 0x27, - 0xE0, 0x64, 0x02, 0x70, 0x2A, 0x90, 0x81, 0x24, - 0xE0, 0xFF, 0xC3, 0x13, 0x20, 0xE0, 0x09, 0x90, - 0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x28, - 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x01, - 0x70, 0x2D, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x04, - 0xF0, 0x7F, 0x01, 0xB1, 0xD2, 0x80, 0x20, 0x90, - 0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, - 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, - 0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07, - 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90, - 0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7, - 0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74, - 0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04, - 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, - 0x01, 0x5F, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, - 0x08, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, - 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, - 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50, - 0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, - 0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, - 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x2A, 0xE0, - 0x64, 0x0C, 0x60, 0x0C, 0xE4, 0xFD, 0x7F, 0x0C, - 0x12, 0x47, 0x3D, 0xE4, 0xFF, 0x12, 0x4F, 0x0D, - 0x22, 0xE4, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x06, - 0xA9, 0xE0, 0x90, 0x81, 0x4C, 0xF0, 0xE0, 0x54, - 0xC0, 0x70, 0x0D, 0x90, 0x81, 0x2B, 0xE0, 0x54, - 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x02, 0x47, 0x2A, - 0x90, 0x81, 0x4C, 0xE0, 0x30, 0xE6, 0x21, 0x90, - 0x81, 0x27, 0xE0, 0x64, 0x01, 0x70, 0x20, 0x90, - 0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, - 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, - 0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07, - 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90, - 0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7, - 0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74, - 0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04, - 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0xE4, - 0xFE, 0xEF, 0xC3, 0x13, 0xFD, 0xEF, 0x30, 0xE0, - 0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, 0xED, 0xF0, - 0xAF, 0x06, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, - 0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1A, - 0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07, - 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, 0x90, - 0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00, - 0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, - 0x22, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, - 0x73, 0xE1, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, - 0x03, 0x12, 0x49, 0xDD, 0x22, 0x90, 0x81, 0x27, - 0xE0, 0x60, 0x35, 0x90, 0x06, 0x92, 0xE0, 0x30, - 0xE1, 0x24, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, - 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, - 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50, - 0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, - 0x06, 0x92, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x81, - 0x24, 0xE0, 0x54, 0xEF, 0xF0, 0x12, 0x47, 0x2A, - 0x22, 0x12, 0x71, 0x48, 0x90, 0x81, 0x4D, 0xEF, - 0xF0, 0x90, 0x81, 0x24, 0x30, 0xE0, 0x06, 0xE0, - 0x44, 0x01, 0xF0, 0x80, 0x04, 0xE0, 0x54, 0xFE, - 0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x30, 0xE6, 0x11, - 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x04, 0xE4, - 0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x80, - 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x30, 0xE0, 0x1A, - 0x90, 0x81, 0x32, 0xE4, 0xF0, 0xA3, 0x74, 0x07, - 0xF0, 0x90, 0x81, 0x32, 0xA3, 0xE0, 0x90, 0x05, - 0x58, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD, - 0xF0, 0x22, 0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22, - 0xF0, 0x22, 0x90, 0x81, 0x4A, 0xE0, 0x60, 0x0F, - 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x01, - 0xF0, 0x90, 0x05, 0xFD, 0xE0, 0x04, 0xF0, 0x22, - 0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, - 0x54, 0x03, 0x30, 0xE0, 0x27, 0xEF, 0x54, 0xBF, - 0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, - 0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, - 0x10, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9, - 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x04, - 0xF0, 0x12, 0x47, 0x2A, 0xE4, 0xFF, 0x90, 0x81, - 0x45, 0xE0, 0x30, 0xE0, 0x48, 0x90, 0x81, 0x49, - 0xE0, 0xFD, 0x60, 0x41, 0x74, 0x01, 0x7E, 0x00, - 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, - 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, 0xE0, - 0xE0, 0xFB, 0xEF, 0x5B, 0x60, 0x06, 0xE4, 0x90, - 0x81, 0x49, 0xF0, 0x22, 0x90, 0x81, 0x47, 0xE0, - 0xD3, 0x9D, 0x50, 0x10, 0x90, 0x01, 0xC7, 0x74, - 0x10, 0xF0, 0x11, 0xBE, 0x90, 0x81, 0x45, 0xE0, - 0x54, 0xFE, 0xF0, 0x22, 0x12, 0x4F, 0x0B, 0x90, - 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x80, - 0x3C, 0xE0, 0x64, 0x02, 0x60, 0x07, 0x90, 0x06, - 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x81, - 0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, - 0x01, 0x30, 0xE0, 0x2C, 0xEF, 0x54, 0x7F, 0xF0, - 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, 0x30, - 0xE1, 0x06, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x0F, - 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74, - 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x90, - 0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, 0x47, 0x2A, - 0x7F, 0x01, 0x01, 0x6E, 0xC3, 0xEE, 0x94, 0x01, - 0x40, 0x0A, 0x0D, 0xED, 0x13, 0x90, 0xFD, 0x10, - 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xC3, 0xEE, 0x94, - 0x01, 0x40, 0x24, 0x90, 0xFD, 0x11, 0xE0, 0x6D, - 0x70, 0x1A, 0x90, 0x01, 0x17, 0xE0, 0xB5, 0x05, - 0x0D, 0x90, 0x01, 0xE4, 0x74, 0x77, 0xF0, 0x90, - 0xFD, 0x11, 0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04, - 0x90, 0xFD, 0x11, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, - 0xE4, 0x90, 0x81, 0x4E, 0xF0, 0xA3, 0xF0, 0xA3, - 0xF0, 0x90, 0x00, 0x83, 0xE0, 0x90, 0x81, 0x4E, - 0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x81, - 0x4E, 0xE0, 0xFF, 0xB5, 0x06, 0x01, 0x22, 0xC3, - 0x90, 0x81, 0x50, 0xE0, 0x94, 0x64, 0x90, 0x81, - 0x4F, 0xE0, 0x94, 0x00, 0x40, 0x0D, 0x90, 0x01, - 0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x4E, - 0xE0, 0xFF, 0x22, 0x90, 0x81, 0x4F, 0xE4, 0x75, - 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x80, 0xC2, 0x74, - 0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, - 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, - 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3, - 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, - 0x12, 0xED, 0xF0, 0x90, 0x82, 0x11, 0xEF, 0xF0, - 0xD3, 0x94, 0x07, 0x50, 0x70, 0xE0, 0xFF, 0x74, - 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, - 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x47, 0xE0, - 0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, 0x90, - 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, - 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, - 0x90, 0x00, 0x46, 0xE0, 0x4F, 0xFD, 0x7F, 0x46, - 0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0, 0x60, - 0x18, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, - 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, - 0xFC, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x4F, 0x80, - 0x17, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, - 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, - 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x5F, - 0xFD, 0x7F, 0x45, 0x80, 0x7E, 0x90, 0x82, 0x11, - 0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, 0xFF, - 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, - 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x43, - 0xE0, 0x5F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, - 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, - 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, - 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, 0x7F, - 0x43, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0, - 0x60, 0x1D, 0x90, 0x82, 0x11, 0xE0, 0x24, 0x04, - 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, - 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x42, - 0xE0, 0x4F, 0xFD, 0x7F, 0x42, 0x80, 0x1C, 0x90, - 0x82, 0x11, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, - 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, - 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x5F, - 0xFD, 0x7F, 0x42, 0x12, 0x32, 0x1E, 0xD0, 0xD0, - 0x92, 0xAF, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54, - 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, - 0x81, 0x2B, 0xF0, 0x22, 0xEF, 0x24, 0xFE, 0x60, - 0x0C, 0x04, 0x70, 0x28, 0x90, 0x81, 0x2D, 0x74, - 0x01, 0xF0, 0xA3, 0xF0, 0x22, 0xED, 0x70, 0x0A, - 0x90, 0x81, 0x3B, 0xE0, 0x90, 0x81, 0x2D, 0xF0, - 0x80, 0x05, 0x90, 0x81, 0x2D, 0xED, 0xF0, 0x90, - 0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x90, 0x81, 0x25, - 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x12, 0x4E, 0xAB, - 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, - 0x74, 0x01, 0xF0, 0x80, 0x67, 0x90, 0x81, 0x2B, - 0xE0, 0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01, - 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x56, 0x90, 0x81, - 0x29, 0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08, - 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x44, - 0xEF, 0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74, - 0x08, 0xF0, 0x80, 0x38, 0x90, 0x81, 0x2B, 0xE0, - 0x30, 0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10, - 0xF0, 0x80, 0x29, 0x90, 0x81, 0x25, 0xE0, 0x13, - 0x13, 0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01, - 0xB8, 0x74, 0x20, 0xF0, 0x80, 0x16, 0x90, 0x81, - 0x3E, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, - 0x80, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, - 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, - 0x04, 0xF0, 0x7F, 0x00, 0x22, 0xEF, 0x60, 0x42, - 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x3A, - 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFE, 0xF0, 0x90, - 0x05, 0x22, 0x74, 0x0F, 0xF0, 0x90, 0x06, 0x04, - 0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0xFF, 0x12, 0x4F, - 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x24, 0xE0, - 0x44, 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x06, - 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x01, - 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, - 0x08, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F, - 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, - 0x90, 0x81, 0x2A, 0x74, 0x02, 0xF0, 0x90, 0x81, - 0x23, 0xF0, 0x22, 0x12, 0x54, 0x65, 0x90, 0x81, - 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0, - 0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13, - 0x54, 0x3F, 0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB, - 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, - 0x54, 0x07, 0x70, 0x42, 0x80, 0x3D, 0x90, 0x81, - 0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0, - 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x30, 0xE0, 0xFF, - 0xB4, 0x01, 0x02, 0x80, 0x04, 0xEF, 0xB4, 0x02, - 0x06, 0x90, 0x05, 0x58, 0xE0, 0x04, 0xF0, 0x90, - 0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0, - 0xD3, 0x9F, 0x40, 0x0F, 0x90, 0x80, 0xDE, 0xE0, - 0xB4, 0x01, 0x0B, 0x90, 0x81, 0x25, 0xE0, 0x54, - 0xFB, 0xF0, 0x22, 0x12, 0x47, 0x2A, 0x22, 0x22, - 0x90, 0x05, 0x2B, 0xE0, 0x7F, 0x00, 0x30, 0xE7, - 0x02, 0x7F, 0x01, 0x22, 0x90, 0x05, 0x22, 0x74, - 0xFF, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, - 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22, - 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x12, - 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0, - 0x22, 0x12, 0x49, 0xE3, 0x90, 0x81, 0x22, 0x74, - 0x02, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F, - 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, - 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xAE, - 0x07, 0x12, 0x51, 0x73, 0xBF, 0x01, 0x12, 0x90, - 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, 0x0A, 0xAF, - 0x06, 0x7D, 0x01, 0x12, 0x47, 0x3D, 0x7F, 0x01, - 0x22, 0x7F, 0x00, 0x22, 0x90, 0x01, 0x57, 0xE0, - 0x60, 0x48, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, - 0x02, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, - 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0C, 0xEF, 0x54, - 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, - 0xF0, 0x22, 0x90, 0x81, 0x30, 0xE0, 0x04, 0xF0, - 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xEF, 0xF0, 0x90, - 0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0, - 0xD3, 0x9F, 0x40, 0x0E, 0x90, 0x80, 0xDE, 0xE0, - 0xB4, 0x01, 0x07, 0x90, 0x81, 0x25, 0xE0, 0x54, - 0xFB, 0xF0, 0x22, 0x90, 0x80, 0x3F, 0xE0, 0xFF, - 0x7D, 0x01, 0x12, 0x6D, 0x69, 0x8E, 0x54, 0x8F, - 0x55, 0xAD, 0x55, 0xAC, 0x54, 0xAF, 0x53, 0x12, - 0x4F, 0x82, 0xAF, 0x55, 0xAE, 0x54, 0x90, 0x04, - 0x80, 0xE0, 0x54, 0x0F, 0xFD, 0xAC, 0x07, 0x74, - 0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, - 0x83, 0xE0, 0x44, 0x01, 0xF0, 0x74, 0x11, 0x2C, - 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, - 0x54, 0xFB, 0xF0, 0xAC, 0x07, 0x74, 0x16, 0x2C, - 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, - 0x44, 0xFA, 0xF0, 0x74, 0x15, 0x2C, 0xF5, 0x82, - 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x1F, - 0xF0, 0xAC, 0x07, 0x74, 0x06, 0x2C, 0xF5, 0x82, - 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x0F, - 0xF0, 0x90, 0x04, 0x53, 0xE4, 0xF0, 0x90, 0x04, - 0x52, 0xF0, 0x90, 0x04, 0x51, 0x74, 0xFF, 0xF0, - 0x90, 0x04, 0x50, 0x74, 0xFD, 0xF0, 0x74, 0x14, - 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, - 0xE0, 0x54, 0xC0, 0x4D, 0xFD, 0x74, 0x14, 0x2F, - 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xED, - 0xF0, 0x22, 0xAB, 0x07, 0xAA, 0x06, 0xED, 0x2B, - 0xFB, 0xE4, 0x3A, 0xFA, 0xC3, 0x90, 0x80, 0xDB, - 0xE0, 0x9B, 0x90, 0x80, 0xDA, 0xE0, 0x9A, 0x50, - 0x13, 0xA3, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80, - 0xDA, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0xEB, 0x9F, - 0xFB, 0xEA, 0x9E, 0xFA, 0xEA, 0x90, 0xFD, 0x11, - 0xF0, 0xAF, 0x03, 0x74, 0x00, 0x2F, 0xF5, 0x82, - 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x22, - 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, - 0x81, 0x42, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, - 0xC3, 0x13, 0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01, - 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x43, 0xF0, 0x22, - 0x90, 0x81, 0x45, 0xE0, 0x30, 0xE0, 0x2D, 0x90, - 0x81, 0x48, 0xE0, 0x04, 0xF0, 0xE0, 0xFF, 0x90, - 0x81, 0x46, 0xE0, 0xB5, 0x07, 0x1E, 0x90, 0x06, - 0x92, 0xE0, 0x54, 0x1C, 0x70, 0x0B, 0x12, 0x4F, - 0x0B, 0x90, 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x80, - 0x06, 0x90, 0x06, 0x92, 0x74, 0x1C, 0xF0, 0xE4, - 0x90, 0x81, 0x48, 0xF0, 0x22, 0x00, 0xBB, 0x8E, -}; diff --git a/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c b/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c index e4f20da91b43..bb43793fd1ec 100644 --- a/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c +++ b/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c @@ -1276,407 +1276,6 @@ static void phy_LCCalibrate_8188E(struct adapter *adapt, bool is2t) } } -/* Analog Pre-distortion calibration */ -#define APK_BB_REG_NUM 8 -#define APK_CURVE_REG_NUM 4 -#define PATH_NUM 2 - -static void phy_APCalibrate_8188E(struct adapter *adapt, s8 delta, bool is2t) -{ - struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); - struct odm_dm_struct *dm_odm = &pHalData->odmpriv; - u32 regD[PATH_NUM]; - u32 tmpreg, index, offset, apkbound; - u8 path, i, pathbound = PATH_NUM; - u32 BB_backup[APK_BB_REG_NUM]; - u32 BB_REG[APK_BB_REG_NUM] = { - rFPGA1_TxBlock, rOFDM0_TRxPathEnable, - rFPGA0_RFMOD, rOFDM0_TRMuxPar, - rFPGA0_XCD_RFInterfaceSW, rFPGA0_XAB_RFInterfaceSW, - rFPGA0_XA_RFInterfaceOE, rFPGA0_XB_RFInterfaceOE }; - u32 BB_AP_MODE[APK_BB_REG_NUM] = { - 0x00000020, 0x00a05430, 0x02040000, - 0x000800e4, 0x00204000 }; - u32 BB_normal_AP_MODE[APK_BB_REG_NUM] = { - 0x00000020, 0x00a05430, 0x02040000, - 0x000800e4, 0x22204000 }; - - u32 AFE_backup[IQK_ADDA_REG_NUM]; - u32 AFE_REG[IQK_ADDA_REG_NUM] = { - rFPGA0_XCD_SwitchControl, rBlue_Tooth, - rRx_Wait_CCA, rTx_CCK_RFON, - rTx_CCK_BBON, rTx_OFDM_RFON, - rTx_OFDM_BBON, rTx_To_Rx, - rTx_To_Tx, rRx_CCK, - rRx_OFDM, rRx_Wait_RIFS, - rRx_TO_Rx, rStandby, - rSleep, rPMPD_ANAEN }; - - u32 MAC_backup[IQK_MAC_REG_NUM]; - u32 MAC_REG[IQK_MAC_REG_NUM] = { - REG_TXPAUSE, REG_BCN_CTRL, - REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; - - u32 APK_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { - {0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c}, - {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e} - }; - - u32 APK_normal_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { - {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, /* path settings equal to path b settings */ - {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c} - }; - - u32 APK_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { - {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d}, - {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050} - }; - - u32 APK_normal_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { - {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, /* path settings equal to path b settings */ - {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a} - }; - - u32 AFE_on_off[PATH_NUM] = { - 0x04db25a4, 0x0b1b25a4}; /* path A on path B off / path A off path B on */ - - u32 APK_offset[PATH_NUM] = { - rConfig_AntA, rConfig_AntB}; - - u32 APK_normal_offset[PATH_NUM] = { - rConfig_Pmpd_AntA, rConfig_Pmpd_AntB}; - - u32 APK_value[PATH_NUM] = { - 0x92fc0000, 0x12fc0000}; - - u32 APK_normal_value[PATH_NUM] = { - 0x92680000, 0x12680000}; - - s8 APK_delta_mapping[APK_BB_REG_NUM][13] = { - {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, - {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, - {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, - {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6}, - {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0} - }; - - u32 APK_normal_setting_value_1[13] = { - 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28, - 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3, - 0x12680000, 0x00880000, 0x00880000 - }; - - u32 APK_normal_setting_value_2[16] = { - 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3, - 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025, - 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008, - 0x00050006 - }; - - u32 APK_result[PATH_NUM][APK_BB_REG_NUM]; /* val_1_1a, val_1_2a, val_2a, val_3a, val_4a */ - s32 BB_offset, delta_V, delta_offset; - - if (*(dm_odm->mp_mode) == 1) { - struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx); - pMptCtx->APK_bound[0] = 45; - pMptCtx->APK_bound[1] = 52; - } - - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("==>phy_APCalibrate_8188E() delta %d\n", delta)); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("AP Calibration for %s\n", (is2t ? "2T2R" : "1T1R"))); - if (!is2t) - pathbound = 1; - - /* 2 FOR NORMAL CHIP SETTINGS */ - -/* Temporarily do not allow normal driver to do the following settings - * because these offset and value will cause RF internal PA to be - * unpredictably disabled by HW, such that RF Tx signal will disappear - * after disable/enable card many times on 88CU. RF SD and DD have not - * find the root cause, so we remove these actions temporarily. - */ - if (*(dm_odm->mp_mode) != 1) - return; - /* settings adjust for normal chip */ - for (index = 0; index < PATH_NUM; index++) { - APK_offset[index] = APK_normal_offset[index]; - APK_value[index] = APK_normal_value[index]; - AFE_on_off[index] = 0x6fdb25a4; - } - - for (index = 0; index < APK_BB_REG_NUM; index++) { - for (path = 0; path < pathbound; path++) { - APK_RF_init_value[path][index] = APK_normal_RF_init_value[path][index]; - APK_RF_value_0[path][index] = APK_normal_RF_value_0[path][index]; - } - BB_AP_MODE[index] = BB_normal_AP_MODE[index]; - } - - apkbound = 6; - - /* save BB default value */ - for (index = 0; index < APK_BB_REG_NUM; index++) { - if (index == 0) /* skip */ - continue; - BB_backup[index] = ODM_GetBBReg(dm_odm, BB_REG[index], bMaskDWord); - } - - /* save MAC default value */ - _PHY_SaveMACRegisters(adapt, MAC_REG, MAC_backup); - - /* save AFE default value */ - _PHY_SaveADDARegisters(adapt, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); - - for (path = 0; path < pathbound; path++) { - if (path == RF_PATH_A) { - /* path A APK */ - /* load APK setting */ - /* path-A */ - offset = rPdp_AntA; - for (index = 0; index < 11; index++) { - ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", - offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord))); - offset += 0x04; - } - - ODM_SetBBReg(dm_odm, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); - - offset = rConfig_AntA; - for (; index < 13; index++) { - ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", - offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord))); - offset += 0x04; - } - - /* page-B1 */ - ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x40000000); - - /* path A */ - offset = rPdp_AntA; - for (index = 0; index < 16; index++) { - ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_2[index]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", - offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord))); - - offset += 0x04; - } - ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000); - } else if (path == RF_PATH_B) { - /* path B APK */ - /* load APK setting */ - /* path-B */ - offset = rPdp_AntB; - for (index = 0; index < 10; index++) { - ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", - offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord))); - - offset += 0x04; - } - ODM_SetBBReg(dm_odm, rConfig_Pmpd_AntA, bMaskDWord, 0x12680000); - PHY_SetBBReg(adapt, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); - - offset = rConfig_AntA; - index = 11; - for (; index < 13; index++) { /* offset 0xb68, 0xb6c */ - ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", - offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord))); - offset += 0x04; - } - - /* page-B1 */ - ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x40000000); - - /* path B */ - offset = 0xb60; - for (index = 0; index < 16; index++) { - ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_2[index]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", - offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord))); - - offset += 0x04; - } - ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0); - } - - /* save RF default value */ - regD[path] = PHY_QueryRFReg(adapt, path, RF_TXBIAS_A, bMaskDWord); - - /* Path A AFE all on, path B AFE All off or vise versa */ - for (index = 0; index < IQK_ADDA_REG_NUM; index++) - ODM_SetBBReg(dm_odm, AFE_REG[index], bMaskDWord, AFE_on_off[path]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() offset 0xe70 %x\n", - ODM_GetBBReg(dm_odm, rRx_Wait_CCA, bMaskDWord))); - - /* BB to AP mode */ - if (path == 0) { - for (index = 0; index < APK_BB_REG_NUM; index++) { - if (index == 0) /* skip */ - continue; - else if (index < 5) - ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_AP_MODE[index]); - else if (BB_REG[index] == 0x870) - ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_backup[index]|BIT10|BIT26); - else - ODM_SetBBReg(dm_odm, BB_REG[index], BIT10, 0x0); - } - - ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); - ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); - } else { - /* path B */ - ODM_SetBBReg(dm_odm, rTx_IQK_Tone_B, bMaskDWord, 0x01008c00); - ODM_SetBBReg(dm_odm, rRx_IQK_Tone_B, bMaskDWord, 0x01008c00); - } - - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() offset 0x800 %x\n", - ODM_GetBBReg(dm_odm, 0x800, bMaskDWord))); - - /* MAC settings */ - _PHY_MACSettingCalibration(adapt, MAC_REG, MAC_backup); - - if (path == RF_PATH_A) { - /* Path B to standby mode */ - ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMaskDWord, 0x10000); - } else { - /* Path A to standby mode */ - ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMaskDWord, 0x10000); - ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f); - ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE2, bMaskDWord, 0x20103); - } - - delta_offset = ((delta+14)/2); - if (delta_offset < 0) - delta_offset = 0; - else if (delta_offset > 12) - delta_offset = 12; - - /* AP calibration */ - for (index = 0; index < APK_BB_REG_NUM; index++) { - if (index != 1) /* only DO PA11+PAD01001, AP RF setting */ - continue; - - tmpreg = APK_RF_init_value[path][index]; - if (!dm_odm->RFCalibrateInfo.bAPKThermalMeterIgnore) { - BB_offset = (tmpreg & 0xF0000) >> 16; - - if (!(tmpreg & BIT15)) /* sign bit 0 */ - BB_offset = -BB_offset; - - delta_V = APK_delta_mapping[index][delta_offset]; - - BB_offset += delta_V; - - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, - ("phy_APCalibrate_8188E() APK index %d tmpreg 0x%x delta_V %d delta_offset %d\n", - index, tmpreg, delta_V, delta_offset)); - - if (BB_offset < 0) { - tmpreg = tmpreg & (~BIT15); - BB_offset = -BB_offset; - } else { - tmpreg = tmpreg | BIT15; - } - tmpreg = (tmpreg & 0xFFF0FFFF) | (BB_offset << 16); - } - - ODM_SetRFReg(dm_odm, path, RF_IPA_A, bMaskDWord, 0x8992e); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xc %x\n", PHY_QueryRFReg(adapt, path, RF_IPA_A, bMaskDWord))); - ODM_SetRFReg(dm_odm, path, RF_AC, bMaskDWord, APK_RF_value_0[path][index]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x0 %x\n", PHY_QueryRFReg(adapt, path, RF_AC, bMaskDWord))); - ODM_SetRFReg(dm_odm, path, RF_TXBIAS_A, bMaskDWord, tmpreg); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xd %x\n", PHY_QueryRFReg(adapt, path, RF_TXBIAS_A, bMaskDWord))); - /* PA11+PAD01111, one shot */ - i = 0; - do { - ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80000000); - ODM_SetBBReg(dm_odm, APK_offset[path], bMaskDWord, APK_value[0]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(dm_odm, APK_offset[path], bMaskDWord))); - ODM_delay_ms(3); - ODM_SetBBReg(dm_odm, APK_offset[path], bMaskDWord, APK_value[1]); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(dm_odm, APK_offset[path], bMaskDWord))); - - ODM_delay_ms(20); - ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000); - - if (path == RF_PATH_A) - tmpreg = ODM_GetBBReg(dm_odm, rAPK, 0x03E00000); - else - tmpreg = ODM_GetBBReg(dm_odm, rAPK, 0xF8000000); - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xbd8[25:21] %x\n", tmpreg)); - - i++; - } while (tmpreg > apkbound && i < 4); - - APK_result[path][index] = tmpreg; - } - } - - /* reload MAC default value */ - _PHY_ReloadMACRegisters(adapt, MAC_REG, MAC_backup); - - /* reload BB default value */ - for (index = 0; index < APK_BB_REG_NUM; index++) { - if (index == 0) /* skip */ - continue; - ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_backup[index]); - } - - /* reload AFE default value */ - reload_adda_reg(adapt, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); - - /* reload RF path default value */ - for (path = 0; path < pathbound; path++) { - ODM_SetRFReg(dm_odm, path, 0xd, bMaskDWord, regD[path]); - if (path == RF_PATH_B) { - ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f); - ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE2, bMaskDWord, 0x20101); - } - - /* note no index == 0 */ - if (APK_result[path][1] > 6) - APK_result[path][1] = 6; - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("apk path %d result %d 0x%x \t", path, 1, APK_result[path][1])); - } - - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\n")); - - for (path = 0; path < pathbound; path++) { - ODM_SetRFReg(dm_odm, path, 0x3, bMaskDWord, - ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][1] << 5) | APK_result[path][1])); - if (path == RF_PATH_A) - ODM_SetRFReg(dm_odm, path, 0x4, bMaskDWord, - ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x00 << 5) | 0x05)); - else - ODM_SetRFReg(dm_odm, path, 0x4, bMaskDWord, - ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x02 << 5) | 0x05)); - ODM_SetRFReg(dm_odm, path, RF_BS_PA_APSET_G9_G11, bMaskDWord, - ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | 0x08)); - } - - dm_odm->RFCalibrateInfo.bAPKdone = true; - - ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("<==phy_APCalibrate_8188E()\n")); -} - -#define DP_BB_REG_NUM 7 -#define DP_RF_REG_NUM 1 -#define DP_RETRY_LIMIT 10 -#define DP_PATH_NUM 2 -#define DP_DPK_NUM 3 -#define DP_DPK_VALUE_NUM 2 - void PHY_IQCalibrate_8188E(struct adapter *adapt, bool recovery) { struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); @@ -1867,28 +1466,6 @@ void PHY_LCCalibrate_8188E(struct adapter *adapt) ("LCK:Finish!!!interface %d\n", dm_odm->InterfaceIndex)); } -void PHY_APCalibrate_8188E(struct adapter *adapt, s8 delta) -{ - struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); - struct odm_dm_struct *dm_odm = &pHalData->odmpriv; - - return; - if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION)) - return; - -#if FOR_BRAZIL_PRETEST != 1 - if (dm_odm->RFCalibrateInfo.bAPKdone) -#endif - return; - - if (dm_odm->RFType == ODM_2T2R) { - phy_APCalibrate_8188E(adapt, delta, true); - } else { - /* For 88C 1T1R */ - phy_APCalibrate_8188E(adapt, delta, false); - } -} - static void phy_setrfpathswitch_8188e(struct adapter *adapt, bool main, bool is2t) { struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); diff --git a/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c index e913a22a6426..5700dbce5b8c 100644 --- a/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c +++ b/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c @@ -85,7 +85,7 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, u8 cut_vers, u8 fab_vers, value &= ~(GET_PWR_CFG_MASK(pwrcfgcmd)); value |= (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd)); - /* Write the value back to sytem register */ + /* Write the value back to system register */ rtw_write8(padapter, offset, value); break; case PWR_CMD_POLLING: diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c index 8c8587754517..0b0c68c9865c 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c @@ -484,7 +484,7 @@ static void ConstructProbeRsp(struct adapter *adapt, u8 *pframe, u32 *pLength, u *pLength = pktlen; } -/* To check if reserved page content is destroyed by beacon beacuse beacon is too large. */ +/* To check if reserved page content is destroyed by beacon because beacon is too large. */ /* 2010.06.23. Added by tynli. */ void CheckFwRsvdPageContent(struct adapter *Adapter) { @@ -496,9 +496,9 @@ void CheckFwRsvdPageContent(struct adapter *Adapter) /* (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */ /* Input: */ /* bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */ -/* so we need to set the packet length to total lengh. */ +/* so we need to set the packet length to total length. */ /* true: At the second time, we should send the first packet (default:beacon) */ -/* to Hw again and set the lengh in descriptor to the real beacon lengh. */ +/* to Hw again and set the length in descriptor to the real beacon length. */ /* 2009.10.15 by tynli. */ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished) { @@ -671,7 +671,7 @@ _func_enter_; DBG_88E("%s: 1 Download RSVD success! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll); /* */ /* We just can send the reserved page twice during the time that Tx thread is stopped (e.g. pnpsetpower) */ - /* becuase we need to free the Tx BCN Desc which is used by the first reserved page packet. */ + /* because we need to free the Tx BCN Desc which is used by the first reserved page packet. */ /* At run time, we cannot get the Tx Desc until it is released in TxHandleInterrupt() so we will return */ /* the beacon TCB in the following code. 2011.11.23. by tynli. */ /* */ diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index 292ba62d722f..52b3fba0fae1 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -19,6 +19,7 @@ ******************************************************************************/ #define _HAL_INIT_C_ +#include <linux/firmware.h> #include <drv_types.h> #include <rtw_efuse.h> @@ -588,13 +589,15 @@ s32 rtl8188e_FirmwareDownload(struct adapter *padapter) u8 writeFW_retry = 0; u32 fwdl_start_time; struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); - - u8 *FwImage; - u32 FwImageLen; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct device *device = dvobj_to_dev(dvobj); struct rt_firmware *pFirmware = NULL; + const struct firmware *fw; struct rt_firmware_hdr *pFwHdr = NULL; u8 *pFirmwareBuf; - u32 FirmwareLen; + u32 FirmwareLen; + char fw_name[] = "rtlwifi/rtl8188eufw.bin"; + static int log_version; RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__)); pFirmware = (struct rt_firmware *)rtw_zmalloc(sizeof(struct rt_firmware)); @@ -603,27 +606,32 @@ s32 rtl8188e_FirmwareDownload(struct adapter *padapter) goto Exit; } - FwImage = (u8 *)Rtl8188E_FwImageArray; - FwImageLen = Rtl8188E_FWImgArrayLength; - - pFirmware->eFWSource = FW_SOURCE_HEADER_FILE; - - switch (pFirmware->eFWSource) { - case FW_SOURCE_IMG_FILE: - break; - case FW_SOURCE_HEADER_FILE: - if (FwImageLen > FW_8188E_SIZE) { - rtStatus = _FAIL; - RT_TRACE(_module_hal_init_c_, _drv_err_, ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE)); - goto Exit; - } + if (request_firmware(&fw, fw_name, device)) { + rtStatus = _FAIL; + goto Exit; + } + if (!fw) { + pr_err("Firmware %s not available\n", fw_name); + rtStatus = _FAIL; + goto Exit; + } + if (fw->size > FW_8188E_SIZE) { + rtStatus = _FAIL; + RT_TRACE(_module_hal_init_c_, _drv_err_, ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE)); + goto Exit; + } - pFirmware->szFwBuffer = FwImage; - pFirmware->ulFwLength = FwImageLen; - break; + pFirmware->szFwBuffer = kzalloc(FW_8188E_SIZE, GFP_KERNEL); + if (!pFirmware->szFwBuffer) { + rtStatus = _FAIL; + goto Exit; } + memcpy(pFirmware->szFwBuffer, fw->data, fw->size); + pFirmware->ulFwLength = fw->size; pFirmwareBuf = pFirmware->szFwBuffer; FirmwareLen = pFirmware->ulFwLength; + release_firmware(fw); + DBG_88E_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__, FirmwareLen); /* To Check Fw header. Added by tynli. 2009.12.04. */ @@ -633,8 +641,10 @@ s32 rtl8188e_FirmwareDownload(struct adapter *padapter) pHalData->FirmwareSubVersion = pFwHdr->Subversion; pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature); - DBG_88E("%s: fw_ver =%d fw_subver =%d sig = 0x%x\n", - __func__, pHalData->FirmwareVersion, pHalData->FirmwareSubVersion, pHalData->FirmwareSignature); + if (!log_version++) + pr_info("%sFirmware Version %d, SubVersion %d, Signature 0x%x\n", + DRIVER_PREFIX, pHalData->FirmwareVersion, + pHalData->FirmwareSubVersion, pHalData->FirmwareSignature); if (IS_FW_HEADER_EXIST(pFwHdr)) { /* Shift 32 bytes for FW header */ @@ -677,7 +687,7 @@ s32 rtl8188e_FirmwareDownload(struct adapter *padapter) goto Exit; } RT_TRACE(_module_hal_init_c_, _drv_info_, ("Firmware is ready to run!\n")); - + kfree(pFirmware->szFwBuffer); Exit: kfree(pFirmware); @@ -1479,7 +1489,6 @@ static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuse static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) { - bool bRet = false; u16 efuse_addr = *pAddr; u8 badworden = 0; u32 PgWriteSuccess = 0; @@ -1497,7 +1506,6 @@ static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u else return true; } - return bRet; } static bool @@ -1653,7 +1661,7 @@ hal_EfusePgCheckAvailableAddr( { u16 efuse_max_available_len = 0; - /* Change to check TYPE_EFUSE_MAP_LEN , beacuse 8188E raw 256, logic map over 256. */ + /* Change to check TYPE_EFUSE_MAP_LEN , because 8188E raw 256, logic map over 256. */ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len, false); if (Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest) >= efuse_max_available_len) @@ -2100,7 +2108,7 @@ static u8 Hal_GetChnlGroup88E(u8 chnl, u8 *pGroup) if (chnl <= 14) { bIn24G = true; - if (chnl < 3) /* Chanel 1-2 */ + if (chnl < 3) /* Channel 1-2 */ *pGroup = 0; else if (chnl < 6) /* Channel 3-5 */ *pGroup = 1; @@ -2182,7 +2190,7 @@ void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool Auto pHalData->bTXPowerDataReadFromEEPORM = true; for (rfPath = 0; rfPath < pHalData->NumTotalRFPath; rfPath++) { - for (ch = 0; ch <= CHANNEL_MAX_NUMBER; ch++) { + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { bIn24G = Hal_GetChnlGroup88E(ch, &group); if (bIn24G) { pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group]; diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c b/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c index ff468a68e327..68bb96d83c81 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c @@ -559,7 +559,7 @@ static int phy_BB8188E_Config_ParaFile(struct adapter *Adapter) /* */ /* 1. Read PHY_REG.TXT BB INIT!! */ - /* We will seperate as 88C / 92C according to chip version */ + /* We will separate as 88C / 92C according to chip version */ /* */ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG)) rtStatus = _FAIL; @@ -685,7 +685,7 @@ static u8 phy_DbmToTxPwrIdx(struct adapter *Adapter, enum wireless_mode Wireless /* */ /* Tested by MP, we found that CCK Index 0 equals to 8dbm, OFDM legacy equals to */ - /* 3dbm, and OFDM HT equals to 0dbm repectively. */ + /* 3dbm, and OFDM HT equals to 0dbm respectively. */ /* Note: */ /* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */ /* By Bruce, 2008-01-29. */ @@ -1006,12 +1006,12 @@ _PHY_SetBWMode92C( switch (pHalData->CurrentChannelBW) { case HT_CHANNEL_WIDTH_20: regBwOpMode |= BW_OPMODE_20MHZ; - /* 2007/02/07 Mark by Emily becasue we have not verify whether this register works */ + /* 2007/02/07 Mark by Emily because we have not verify whether this register works */ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); break; case HT_CHANNEL_WIDTH_40: regBwOpMode &= ~BW_OPMODE_20MHZ; - /* 2007/02/07 Mark by Emily becasue we have not verify whether this register works */ + /* 2007/02/07 Mark by Emily because we have not verify whether this register works */ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); regRRSR_RSC = (regRRSR_RSC&0x90) | (pHalData->nCur40MhzPrimeSC<<5); rtw_write8(Adapter, REG_RRSR+2, regRRSR_RSC); diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c b/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c index bfdf9b3ce77f..299e03e3daf6 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c @@ -181,7 +181,7 @@ i * Currently, we cannot fully disable driver dynamic * tx power mechanism because it is referenced by BT * coexist mechanism. * In the future, two mechanism shall be separated from - * each other and maintained independantly. */ + * each other and maintained independently. */ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) { TxAGC[RF_PATH_A] = 0x10101010; TxAGC[RF_PATH_B] = 0x10101010; @@ -216,11 +216,11 @@ i * Currently, we cannot fully disable driver dynamic ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value); if (direction == 1) { - /* Increase TX pwoer */ + /* Increase TX power */ TxAGC[0] += pwrtrac_value; TxAGC[1] += pwrtrac_value; } else if (direction == 2) { - /* Decrease TX pwoer */ + /* Decrease TX power */ TxAGC[0] -= pwrtrac_value; TxAGC[1] -= pwrtrac_value; } @@ -292,7 +292,7 @@ static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel, if (pHalData->pwrGroupCnt == 1) chnlGroup = 0; if (pHalData->pwrGroupCnt >= pHalData->PGMaxGroup) { - if (Channel < 3) /* Chanel 1-2 */ + if (Channel < 3) /* Channel 1-2 */ chnlGroup = 0; else if (Channel < 6) /* Channel 3-5 */ chnlGroup = 1; @@ -349,7 +349,7 @@ static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel, } /* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */ /* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */ -/* In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. */ +/* In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */ /* 92d do not need this */ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) writeVal = 0x14141414; diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c index bd8a9ae5d077..8f43f4966f22 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c @@ -332,7 +332,7 @@ static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bag /* 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. */ /* (1) The sequence number of each non-Qos frame / broadcast / multicast / */ - /* mgnt frame should be controled by Hw because Fw will also send null data */ + /* mgnt frame should be controlled by Hw because Fw will also send null data */ /* which we cannot control when Fw LPS enable. */ /* --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */ /* (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */ diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c index 5e656ce45407..cca973211b2f 100644 --- a/drivers/staging/rtl8188eu/hal/usb_halinit.c +++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c @@ -464,7 +464,7 @@ static void _InitRetryFunction(struct adapter *Adapter) /*----------------------------------------------------------------------------- * Function: usb_AggSettingTxUpdate() * - * Overview: Seperate TX/RX parameters update independent for TP detection and + * Overview: Separate TX/RX parameters update independent for TP detection and * dynamic TX/RX aggreagtion parameters update. * * Input: struct adapter * @@ -473,7 +473,7 @@ static void _InitRetryFunction(struct adapter *Adapter) * * Revised History: * When Who Remark - * 12/10/2010 MHC Seperate to smaller function. + * 12/10/2010 MHC Separate to smaller function. * *---------------------------------------------------------------------------*/ static void usb_AggSettingTxUpdate(struct adapter *Adapter) @@ -496,7 +496,7 @@ static void usb_AggSettingTxUpdate(struct adapter *Adapter) /*----------------------------------------------------------------------------- * Function: usb_AggSettingRxUpdate() * - * Overview: Seperate TX/RX parameters update independent for TP detection and + * Overview: Separate TX/RX parameters update independent for TP detection and * dynamic TX/RX aggreagtion parameters update. * * Input: struct adapter * @@ -505,7 +505,7 @@ static void usb_AggSettingTxUpdate(struct adapter *Adapter) * * Revised History: * When Who Remark - * 12/10/2010 MHC Seperate to smaller function. + * 12/10/2010 MHC Separate to smaller function. * *---------------------------------------------------------------------------*/ static void @@ -847,7 +847,7 @@ _func_enter_; /* */ /* Init CR MACTXEN, MACRXEN after setting RxFF boundary REG_TRXFF_BNDY to patch */ - /* Hw bug which Hw initials RxFF boundry size to a value which is larger than the real Rx buffer size in 88E. */ + /* Hw bug which Hw initials RxFF boundary size to a value which is larger than the real Rx buffer size in 88E. */ /* */ /* Enable MACTXEN/MACRXEN block */ value16 = rtw_read16(Adapter, REG_CR); diff --git a/drivers/staging/rtl8188eu/hal/usb_ops_linux.c b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c index bc564169b2f0..787763ef74c6 100644 --- a/drivers/staging/rtl8188eu/hal/usb_ops_linux.c +++ b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c @@ -547,6 +547,8 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete : purb->status(%d) != 0\n", purb->status)); DBG_88E("###=> usb_read_port_complete => urb status(%d)\n", purb->status); + skb_put(precvbuf->pskb, purb->actual_length); + precvbuf->pskb = NULL; if (rtw_inc_and_chk_continual_urb_error(adapter_to_dvobj(adapt))) adapt->bSurpriseRemoved = true; @@ -605,68 +607,68 @@ _func_enter_; return _FAIL; } + if (!precvbuf) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port:precvbuf==NULL\n")); + return _FAIL; + } + if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) { precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); if (NULL != precvbuf->pskb) precvbuf->reuse = true; } - if (precvbuf != NULL) { - rtl8188eu_init_recvbuf(adapter, precvbuf); - - /* re-assign for linux based on skb */ - if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) { - precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); - if (precvbuf->pskb == NULL) { - RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("init_recvbuf(): alloc_skb fail!\n")); - DBG_88E("#### usb_read_port() alloc_skb fail!#####\n"); - return _FAIL; - } - - tmpaddr = (size_t)precvbuf->pskb->data; - alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); - skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); - - precvbuf->phead = precvbuf->pskb->head; - precvbuf->pdata = precvbuf->pskb->data; - precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); - precvbuf->pend = skb_end_pointer(precvbuf->pskb); - precvbuf->pbuf = precvbuf->pskb->data; - } else { /* reuse skb */ - precvbuf->phead = precvbuf->pskb->head; - precvbuf->pdata = precvbuf->pskb->data; - precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); - precvbuf->pend = skb_end_pointer(precvbuf->pskb); - precvbuf->pbuf = precvbuf->pskb->data; + rtl8188eu_init_recvbuf(adapter, precvbuf); - precvbuf->reuse = false; + /* re-assign for linux based on skb */ + if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) { + precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); + if (precvbuf->pskb == NULL) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("init_recvbuf(): alloc_skb fail!\n")); + DBG_88E("#### usb_read_port() alloc_skb fail!#####\n"); + return _FAIL; } - precvpriv->rx_pending_cnt++; + tmpaddr = (size_t)precvbuf->pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); + skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); + + precvbuf->phead = precvbuf->pskb->head; + precvbuf->pdata = precvbuf->pskb->data; + precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); + precvbuf->pend = skb_end_pointer(precvbuf->pskb); + precvbuf->pbuf = precvbuf->pskb->data; + } else { /* reuse skb */ + precvbuf->phead = precvbuf->pskb->head; + precvbuf->pdata = precvbuf->pskb->data; + precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); + precvbuf->pend = skb_end_pointer(precvbuf->pskb); + precvbuf->pbuf = precvbuf->pskb->data; + + precvbuf->reuse = false; + } - purb = precvbuf->purb; + precvpriv->rx_pending_cnt++; - /* translate DMA FIFO addr to pipehandle */ - pipe = ffaddr2pipehdl(pdvobj, addr); + purb = precvbuf->purb; - usb_fill_bulk_urb(purb, pusbd, pipe, - precvbuf->pbuf, - MAX_RECVBUF_SZ, - usb_read_port_complete, - precvbuf);/* context is precvbuf */ + /* translate DMA FIFO addr to pipehandle */ + pipe = ffaddr2pipehdl(pdvobj, addr); - err = usb_submit_urb(purb, GFP_ATOMIC); - if ((err) && (err != (-EPERM))) { - RT_TRACE(_module_hci_ops_os_c_, _drv_err_, - ("cannot submit rx in-token(err=0x%.8x), URB_STATUS =0x%.8x", - err, purb->status)); - DBG_88E("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n", - err, purb->status); - ret = _FAIL; - } - } else { + usb_fill_bulk_urb(purb, pusbd, pipe, + precvbuf->pbuf, + MAX_RECVBUF_SZ, + usb_read_port_complete, + precvbuf);/* context is precvbuf */ + + err = usb_submit_urb(purb, GFP_ATOMIC); + if ((err) && (err != (-EPERM))) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, - ("usb_read_port:precvbuf ==NULL\n")); + ("cannot submit rx in-token(err=0x%.8x), URB_STATUS =0x%.8x", + err, purb->status)); + DBG_88E("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n", + err, purb->status); ret = _FAIL; } diff --git a/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h b/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h deleted file mode 100644 index 949c33b9ed68..000000000000 --- a/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h +++ /dev/null @@ -1,28 +0,0 @@ -/****************************************************************************** -* -* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of version 2 of the GNU General Public License 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 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., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA -* -* -******************************************************************************/ -#ifndef __INC_HAL8188E_FW_IMG_H -#define __INC_HAL8188E_FW_IMG_H - -/* V10(1641) */ -#define Rtl8188EFWImgArrayLength 13904 - -extern const u8 Rtl8188EFwImgArray[Rtl8188EFWImgArrayLength]; - -#endif /* __INC_HAL8188E_FW_IMG_H */ diff --git a/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h b/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h index c4769e20a5c3..25cae8147e73 100644 --- a/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h +++ b/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h @@ -75,7 +75,7 @@ enum rf_radio_path { #define MAX_PG_GROUP 13 -#define RF_PATH_MAX 2 +#define RF_PATH_MAX 3 #define MAX_RF_PATH RF_PATH_MAX #define MAX_TX_COUNT 4 /* path numbers */ diff --git a/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h b/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h index 0e06d29b2d2a..9f2969bf8355 100644 --- a/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h +++ b/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h @@ -26,7 +26,7 @@ /* 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */ /* 3. RF register 0x00-2E */ /* 4. Bit Mask for BB/RF register */ -/* 5. Other defintion for BB/RF R/W */ +/* 5. Other definition for BB/RF R/W */ /* */ diff --git a/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h b/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h index fa583f248320..287e9f9eae4a 100644 --- a/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h +++ b/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h @@ -45,8 +45,6 @@ void PHY_IQCalibrate_8188E(struct adapter *Adapter, bool ReCovery); void PHY_LCCalibrate_8188E(struct adapter *pAdapter); /* AP calibrate */ -void PHY_APCalibrate_8188E(struct adapter *pAdapter, s8 delta); - void PHY_DigitalPredistortion_8188E(struct adapter *pAdapter); void _PHY_SaveADDARegisters(struct adapter *pAdapter, u32 *ADDAReg, diff --git a/drivers/staging/rtl8188eu/include/odm.h b/drivers/staging/rtl8188eu/include/odm.h index 4787bacdcad8..eaa4bc1b2255 100644 --- a/drivers/staging/rtl8188eu/include/odm.h +++ b/drivers/staging/rtl8188eu/include/odm.h @@ -283,8 +283,6 @@ struct odm_rate_adapt { /* Declare for common info */ -#define MAX_PATH_NUM_92CS 2 - struct odm_phy_status_info { u8 RxPWDBAll; u8 SignalQuality; /* in 0-100 index. */ @@ -950,7 +948,7 @@ struct odm_dm_struct { struct timer_list FastAntTrainingTimer; }; /* DM_Dynamic_Mechanism_Structure */ -#define ODM_RF_PATH_MAX 2 +#define ODM_RF_PATH_MAX 3 enum ODM_RF_RADIO_PATH { ODM_RF_PATH_A = 0, /* Radio Path A */ diff --git a/drivers/staging/rtl8188eu/include/odm_HWConfig.h b/drivers/staging/rtl8188eu/include/odm_HWConfig.h index 63779f5b2a3c..df5272221bad 100644 --- a/drivers/staging/rtl8188eu/include/odm_HWConfig.h +++ b/drivers/staging/rtl8188eu/include/odm_HWConfig.h @@ -69,7 +69,7 @@ struct phy_rx_agc_info { }; struct phy_status_rpt { - struct phy_rx_agc_info path_agc[2]; + struct phy_rx_agc_info path_agc[3]; u8 ch_corr[2]; u8 cck_sig_qual_ofdm_pwdb_all; u8 cck_agc_rpt_ofdm_cfosho_a; @@ -79,7 +79,7 @@ struct phy_status_rpt { u8 path_cfotail[2]; u8 pcts_mask[2]; s8 stream_rxevm[2]; - u8 path_rxsnr[2]; + u8 path_rxsnr[3]; u8 noise_power_db_lsb; u8 rsvd_2[3]; u8 stream_csi[2]; diff --git a/drivers/staging/rtl8188eu/include/odm_debug.h b/drivers/staging/rtl8188eu/include/odm_debug.h index a9ba6df26b9d..622f4c1418b4 100644 --- a/drivers/staging/rtl8188eu/include/odm_debug.h +++ b/drivers/staging/rtl8188eu/include/odm_debug.h @@ -27,7 +27,7 @@ /* Define the debug levels */ /* */ /* 1. DBG_TRACE and DBG_LOUD are used for normal cases. */ -/* They can help SW engineer to develope or trace states changed */ +/* They can help SW engineer to develop or trace states changed */ /* and also help HW enginner to trace every operation to and from HW, */ /* e.g IO, Tx, Rx. */ /* */ diff --git a/drivers/staging/rtl8188eu/include/odm_precomp.h b/drivers/staging/rtl8188eu/include/odm_precomp.h index 520cbbaac35f..d1d95f4b87a8 100644 --- a/drivers/staging/rtl8188eu/include/odm_precomp.h +++ b/drivers/staging/rtl8188eu/include/odm_precomp.h @@ -31,11 +31,6 @@ #include <drv_types.h> #include <hal_intf.h> -/* 2 Hardware Parameter Files */ - -#include "Hal8188EFWImg_CE.h" - - /* 2 OutSrc Header Files */ #include "odm.h" diff --git a/drivers/staging/rtl8188eu/include/rtw_cmd.h b/drivers/staging/rtl8188eu/include/rtw_cmd.h index 819285b9a781..8cafd7adfdcd 100644 --- a/drivers/staging/rtl8188eu/include/rtw_cmd.h +++ b/drivers/staging/rtl8188eu/include/rtw_cmd.h @@ -745,7 +745,7 @@ struct TDLSoption_param Result: 0x00: success -0x01: sucess, and check Response. +0x01: success, and check Response. 0x02: cmd ignored due to duplicated sequcne number 0x03: cmd dropped due to invalid cmd code 0x04: reserved. diff --git a/drivers/staging/rtl8188eu/include/rtw_led.h b/drivers/staging/rtl8188eu/include/rtw_led.h index 2e618043d353..d0da4fd40d18 100644 --- a/drivers/staging/rtl8188eu/include/rtw_led.h +++ b/drivers/staging/rtl8188eu/include/rtw_led.h @@ -163,14 +163,14 @@ enum LED_STRATEGY_871x { void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction); struct led_priv{ - /* add for led controll */ + /* add for led control */ struct LED_871x SwLed0; struct LED_871x SwLed1; enum LED_STRATEGY_871x LedStrategy; u8 bRegUseLed; void (*LedControlHandler)(struct adapter *padapter, enum LED_CTL_MODE LedAction); - /* add for led controll */ + /* add for led control */ }; #define rtw_led_control(adapt, action) \ diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h index 22538e61695a..4a7143e0eed0 100644 --- a/drivers/staging/rtl8188eu/include/rtw_mlme.h +++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h @@ -53,11 +53,11 @@ #define WIFI_SITE_MONITOR 0x00000800 /* to indicate the station is under site surveying */ #define WIFI_MP_STATE 0x00010000 -#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continous tx background */ -#define WIFI_MP_CTX_ST 0x00040000 /* in continous tx with single-tone */ -#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continous tx background due to out of skb */ -#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continous tx */ -#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in continous tx with carrier suppression */ +#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continuous tx background */ +#define WIFI_MP_CTX_ST 0x00040000 /* in continuous tx with single-tone */ +#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continuous tx background due to out of skb */ +#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continuous tx */ +#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in continuous tx with carrier suppression */ #define WIFI_MP_LPBK_STATE 0x00400000 #define _FW_UNDER_LINKING WIFI_UNDER_LINKING @@ -239,7 +239,7 @@ struct wifidirect_info { u8 profileindex; /* Used to point to the index of profileinfo array */ u8 peer_operating_ch; u8 find_phase_state_exchange_cnt; - /* The device password ID for group negotation */ + /* The device password ID for group negotiation */ u16 device_password_id_for_nego; u8 negotiation_dialog_token; /* SSID information for group negotitation */ diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h index 853ab80a2b86..b1bfa2e30fdb 100644 --- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h @@ -107,7 +107,7 @@ extern unsigned char WMM_PARA_OUI[]; /* Note: */ /* We just add new channel plan when the new channel plan is different * from any of the following channel plan. */ -/* If you just wnat to customize the acitions(scan period or join actions) +/* If you just want to customize the actions(scan period or join actions) * about one of the channel plan, */ /* customize them in struct rt_channel_info in the RT_CHANNEL_LIST. */ enum RT_CHANNEL_DOMAIN { diff --git a/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h b/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h index 3ad22076de3f..30fd17f23bf1 100644 --- a/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h +++ b/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h @@ -56,7 +56,7 @@ /* 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */ /* 3. RF register 0x00-2E */ /* 4. Bit Mask for BB/RF register */ -/* 5. Other defintion for BB/RF R/W */ +/* 5. Other definition for BB/RF R/W */ /* */ diff --git a/drivers/staging/rtl8188eu/include/rtw_recv.h b/drivers/staging/rtl8188eu/include/rtw_recv.h index bae8885c57f9..be9c30c57419 100644 --- a/drivers/staging/rtl8188eu/include/rtw_recv.h +++ b/drivers/staging/rtl8188eu/include/rtw_recv.h @@ -83,7 +83,7 @@ struct signal_stat { u32 total_num; /* num of valid elements */ u32 total_val; /* sum of valid elements */ }; -#define MAX_PATH_NUM_92CS 2 +#define MAX_PATH_NUM_92CS 3 struct phy_info { u8 RxPWDBAll; u8 SignalQuality; /* in 0-100 index. */ diff --git a/drivers/staging/rtl8188eu/include/rtw_rf.h b/drivers/staging/rtl8188eu/include/rtw_rf.h index 089ecee6c1f9..2df88370de59 100644 --- a/drivers/staging/rtl8188eu/include/rtw_rf.h +++ b/drivers/staging/rtl8188eu/include/rtw_rf.h @@ -119,7 +119,7 @@ enum ht_channel_width { }; /* */ -/* Represent Extention Channel Offset in HT Capabilities */ +/* Represent Extension Channel Offset in HT Capabilities */ /* This is available only in 40Mhz mode. */ /* */ enum ht_extchnl_offset { diff --git a/drivers/staging/rtl8188eu/include/sta_info.h b/drivers/staging/rtl8188eu/include/sta_info.h index 3ed2a39741ad..3e909db1d41a 100644 --- a/drivers/staging/rtl8188eu/include/sta_info.h +++ b/drivers/staging/rtl8188eu/include/sta_info.h @@ -338,7 +338,7 @@ struct sta_priv { */ struct sta_info *sta_aid[NUM_STA]; - u16 sta_dz_bitmap;/* only support 15 stations, staion aid bitmap + u16 sta_dz_bitmap;/* only support 15 stations, station aid bitmap * for sleeping sta. */ u16 tim_bitmap; /* only support 15 stations, aid=0~15 mapping * bit0~bit15 */ diff --git a/drivers/staging/rtl8188eu/include/wifi.h b/drivers/staging/rtl8188eu/include/wifi.h index a615659f9471..84e519974199 100644 --- a/drivers/staging/rtl8188eu/include/wifi.h +++ b/drivers/staging/rtl8188eu/include/wifi.h @@ -984,7 +984,7 @@ enum ht_cap_ampdu_factor { #define P2P_PROVISION_TIMEOUT 5000 /* 3 seconds timeout for sending the prov disc request concurrent mode */ #define P2P_CONCURRENT_PROVISION_TIME 3000 -/* 5 seconds timeout for receiving the group negotation response */ +/* 5 seconds timeout for receiving the group negotiation response */ #define P2P_GO_NEGO_TIMEOUT 5000 /* 3 seconds timeout for sending the negotiation request under concurrent mode */ #define P2P_CONCURRENT_GO_NEGO_TIME 3000 diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 95953ebc0279..ae5458770234 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -938,7 +938,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev, memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN); if (pPMK->cmd == IW_PMKSA_ADD) { DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n"); - if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN) == true) + if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN)) return ret; else ret = true; @@ -1039,7 +1039,7 @@ static int rtw_wx_get_range(struct net_device *dev, range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ - range->avg_qual.level = 20 + -98; + range->avg_qual.level = 178; /* -78 dBm */ range->avg_qual.noise = 0; range->avg_qual.updated = 7; /* Updated all three */ @@ -1074,7 +1074,7 @@ static int rtw_wx_get_range(struct net_device *dev, /* The following code will proivde the security capability to network manager. */ /* If the driver doesn't provide this capability to network manager, */ -/* the WPA/WPA2 routers can't be choosen in the network manager. */ +/* the WPA/WPA2 routers can't be chosen in the network manager. */ /* #define IW_SCAN_CAPA_NONE 0x00 @@ -1373,7 +1373,7 @@ _func_enter_; } } - /* it has still some scan paramater to parse, we only do this now... */ + /* it has still some scan parameter to parse, we only do this now... */ _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT); } else { _status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); @@ -2626,7 +2626,7 @@ static int rtw_get_ap_info(struct net_device *dev, return -EINVAL; } - if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN) == true) { + if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN)) { /* BSSID match, then check if supporting wpa/wpa2 */ DBG_88E("BSSID:%pM\n", (bssid)); @@ -2961,7 +2961,7 @@ static int rtw_p2p_get_status(struct net_device *dev, /* Commented by Albert 20110520 */ /* This function will return the config method description */ -/* This config method description will show us which config method the remote P2P device is intented to use */ +/* This config method description will show us which config method the remote P2P device is intended to use */ /* by sending the provisioning discovery request frame. */ static int rtw_p2p_get_req_cm(struct net_device *dev, @@ -3413,7 +3413,7 @@ static int rtw_p2p_get_invitation_procedure(struct net_device *dev, /* +8 is for the str "InvProc =", we have to clear it at wrqu->data.pointer */ /* Commented by Ouden 20121226 */ - /* The application wants to know P2P initation procedure is support or not. */ + /* The application wants to know P2P initiation procedure is supported or not. */ /* Format: iwpriv wlanx p2p_get2 InvProc = 00:E0:4C:00:00:05 */ DBG_88E("[%s] data = %s\n", __func__, (char *)extra); @@ -4040,7 +4040,7 @@ static int rtw_rereg_nd_name(struct net_device *dev, if (0 != ret) goto exit; - if (!memcmp(rereg_priv->old_ifname, "disable%d", 9) == true) { + if (!memcmp(rereg_priv->old_ifname, "disable%d", 9)) { padapter->ledpriv.bRegUseLed = rereg_priv->old_bRegUseLed; rtw_hal_sw_led_init(padapter); rtw_ips_mode_req(&padapter->pwrctrlpriv, rereg_priv->old_ips_mode); @@ -4049,7 +4049,7 @@ static int rtw_rereg_nd_name(struct net_device *dev, strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ); rereg_priv->old_ifname[IFNAMSIZ-1] = 0; - if (!memcmp(new_ifname, "disable%d", 9) == true) { + if (!memcmp(new_ifname, "disable%d", 9)) { DBG_88E("%s disable\n", __func__); /* free network queue for Android's timming issue */ rtw_free_network_queue(padapter, true); @@ -4884,7 +4884,6 @@ static int set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid) case _TKIP_: case _TKIP_WTMIC_: case _AES_: - keylen = 16; default: keylen = 16; } @@ -6146,7 +6145,7 @@ static int rtw_mp_efuse_set(struct net_device *dev, for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]); - /* Change to check TYPE_EFUSE_MAP_LEN, beacuse 8188E raw 256, logic map over 256. */ + /* Change to check TYPE_EFUSE_MAP_LEN, because 8188E raw 256, logic map over 256. */ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_size, false); if ((addr+cnts) > max_available_size) { DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts); @@ -6221,7 +6220,7 @@ static int rtw_mp_efuse_set(struct net_device *dev, for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]); - /* Change to check TYPE_EFUSE_MAP_LEN, beacuse 8188E raw 256, logic map over 256. */ + /* Change to check TYPE_EFUSE_MAP_LEN, because 8188E raw 256, logic map over 256. */ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_size, false); if ((addr+cnts) > max_available_size) { DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts); diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index 63bc913eba6d..da9f0d5f76f7 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -85,7 +85,7 @@ static int rtw_uapsd_acvi_en; static int rtw_uapsd_acvo_en; int rtw_ht_enable = 1; -int rtw_cbw40_enable = 3; /* 0 :diable, bit(0): enable 2.4g, bit(1): enable 5g */ +int rtw_cbw40_enable = 3; /* 0 :disable, bit(0): enable 2.4g, bit(1): enable 5g */ int rtw_ampdu_enable = 1;/* for enable tx_ampdu */ static int rtw_rx_stbc = 1;/* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */ static int rtw_ampdu_amsdu;/* 0: disabled, 1:enabled, 2:auto */ diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c index 4e0bfb7e153b..5a9e9e4558aa 100644 --- a/drivers/staging/rtl8188eu/os_dep/osdep_service.c +++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c @@ -627,13 +627,14 @@ RETURN: int rtw_change_ifname(struct adapter *padapter, const char *ifname) { struct net_device *pnetdev; - struct net_device *cur_pnetdev = padapter->pnetdev; + struct net_device *cur_pnetdev; struct rereg_nd_name_data *rereg_priv; int ret; if (!padapter) goto error; + cur_pnetdev = padapter->pnetdev; rereg_priv = &padapter->rereg_nd_name_priv; /* free the old_pnetdev */ @@ -794,7 +795,7 @@ void *rtw_cbuf_pop(struct rtw_cbuf *cbuf) } /** - * rtw_cbuf_alloc - allocte a rtw_cbuf with given size and do initialization + * rtw_cbuf_alloc - allocate a rtw_cbuf with given size and do initialization * @size: size of pointer * * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c index e2f4e7d77170..3852ff43810d 100644 --- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c @@ -77,8 +77,7 @@ int rtw_os_recvbuf_resource_alloc(struct adapter *padapter, int rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf) { - if (precvbuf->purb) - usb_free_urb(precvbuf->purb); + usb_free_urb(precvbuf->purb); return _SUCCESS; } @@ -224,8 +223,7 @@ _func_exit_; _recv_indicatepkt_drop: /* enqueue back to free_recv_queue */ - if (precv_frame) - rtw_free_recvframe(precv_frame, pfree_recv_queue); + rtw_free_recvframe(precv_frame, pfree_recv_queue); _func_exit_; return _FAIL; diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 9ca3180ebaa0..7d14779310d3 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -737,7 +737,7 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, status = _SUCCESS; free_hal_data: - if (status != _SUCCESS && padapter->HalData) + if (status != _SUCCESS) kfree(padapter->HalData); handle_dualmac: if (status != _SUCCESS) diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c index f7b14f8b7b83..1260f10944ef 100644 --- a/drivers/staging/rtl8192e/dot11d.c +++ b/drivers/staging/rtl8192e/dot11d.c @@ -151,7 +151,7 @@ void Dot11d_UpdateCountryIe(struct rtllib_device *dev, u8 *pTaddr, MaxChnlNum = pTriple->FirstChnl + j; } - pTriple = (struct chnl_txpow_triple *)((u8*)pTriple + 3); + pTriple = (struct chnl_txpow_triple *)((u8 *)pTriple + 3); } UPDATE_CIE_SRC(dev, pTaddr); diff --git a/drivers/staging/rtl8192e/dot11d.h b/drivers/staging/rtl8192e/dot11d.h index 71f4549a378f..fb7683fa5ffd 100644 --- a/drivers/staging/rtl8192e/dot11d.h +++ b/drivers/staging/rtl8192e/dot11d.h @@ -38,7 +38,7 @@ enum dot11d_state { /** * struct rt_dot11d_info * @CountryIeLen: value greater than 0 if @CountryIeBuf contains * valid country information element. - * @chanell_map: holds channel values + * @channel_map: holds channel values * 0 - invalid, * 1 - valid (active scan), * 2 - valid (passive scan) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 74fbd70d5838..6616b3a20bc9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1866,15 +1866,15 @@ static void rtl8192_TranslateRxSignalStuff(struct net_device *dev, type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; - bpacket_match_bssid = ((RTLLIB_FTYPE_CTL != type) && - (!compare_ether_addr(priv->rtllib-> - current_network.bssid, - (fc & RTLLIB_FCTL_TODS) ? hdr->addr1 : - (fc & RTLLIB_FCTL_FROMDS) ? hdr->addr2 : hdr->addr3)) - && (!pstats->bHwError) && (!pstats->bCRC) && (!pstats->bICV)); - bpacket_toself = bpacket_match_bssid && /* check this */ - (!compare_ether_addr(praddr, - priv->rtllib->dev->dev_addr)); + bpacket_match_bssid = + ((RTLLIB_FTYPE_CTL != type) && + ether_addr_equal(priv->rtllib->current_network.bssid, + (fc & RTLLIB_FCTL_TODS) ? hdr->addr1 : + (fc & RTLLIB_FCTL_FROMDS) ? hdr->addr2 : + hdr->addr3) && + (!pstats->bHwError) && (!pstats->bCRC) && (!pstats->bICV)); + bpacket_toself = bpacket_match_bssid && /* check this */ + ether_addr_equal(praddr, priv->rtllib->dev->dev_addr); if (WLAN_FC_GET_FRAMETYPE(fc) == RTLLIB_STYPE_BEACON) bPacketBeacon = true; if (bpacket_match_bssid) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index e06844355551..b01f6f5c2c44 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1888,9 +1888,8 @@ void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); skb_push(skb, priv->rtllib->tx_headroom); ret = rtl8192_tx(dev, skb); - if (ret != 0) { + if (ret != 0) kfree_skb(skb); - }; if (queue_index != MGNT_QUEUE) { priv->rtllib->stats.tx_bytes += (skb->len - @@ -1898,7 +1897,6 @@ void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, priv->rtllib->stats.tx_packets++; } - return; } @@ -1930,15 +1928,11 @@ int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) tcb_desc->bTxEnableFwCalcDur = 1; skb_push(skb, priv->rtllib->tx_headroom); ret = rtl8192_tx(dev, skb); - if (ret != 0) { + if (ret != 0) kfree_skb(skb); - }; } - - return ret; - } static void rtl8192_tx_isr(struct net_device *dev, int prio) @@ -2982,7 +2976,6 @@ err_rel_rtllib: free_rtllib(dev); DMESG("wlan driver load failed\n"); - pci_set_drvdata(pdev, NULL); err_pci_disable: pci_disable_device(pdev); return err; diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 8aeaed5a987d..8ee80c50303a 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -957,16 +957,15 @@ static void rtllib_rx_extract_addr(struct rtllib_device *ieee, static int rtllib_rx_data_filter(struct rtllib_device *ieee, u16 fc, u8 *dst, u8 *src, u8 *bssid, u8 *addr2) { - u8 zero_addr[ETH_ALEN] = {0}; u8 type, stype; type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); /* Filter frames from different BSS */ - if (((fc & RTLLIB_FCTL_DSTODS) != RTLLIB_FCTL_DSTODS) - && (compare_ether_addr(ieee->current_network.bssid, bssid) != 0) - && memcmp(ieee->current_network.bssid, zero_addr, ETH_ALEN)) { + if (((fc & RTLLIB_FCTL_DSTODS) != RTLLIB_FCTL_DSTODS) && + !ether_addr_equal(ieee->current_network.bssid, bssid) && + !is_zero_ether_addr(ieee->current_network.bssid)) { return -1; } @@ -974,8 +973,8 @@ static int rtllib_rx_data_filter(struct rtllib_device *ieee, u16 fc, if (ieee->IntelPromiscuousModeInfo.bPromiscuousOn && ieee->IntelPromiscuousModeInfo.bFilterSourceStationFrame) { if ((fc & RTLLIB_FCTL_TODS) && !(fc & RTLLIB_FCTL_FROMDS) && - (compare_ether_addr(dst, ieee->current_network.bssid) != 0) && - (compare_ether_addr(bssid, ieee->current_network.bssid) == 0)) { + !ether_addr_equal(dst, ieee->current_network.bssid) && + ether_addr_equal(bssid, ieee->current_network.bssid)) { return -1; } } @@ -1275,7 +1274,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb, /*Filter pkt not to me*/ multicast = is_multicast_ether_addr(hdr->addr1); unicast = !multicast; - if (unicast && (compare_ether_addr(dev->dev_addr, hdr->addr1) != 0)) { + if (unicast && !ether_addr_equal(dev->dev_addr, hdr->addr1)) { if (ieee->bNetPromiscuousMode) bToOtherSTA = true; else diff --git a/drivers/staging/rtl8192u/dot11d.h b/drivers/staging/rtl8192u/dot11d.h deleted file mode 100644 index 92e7a00f3ee1..000000000000 --- a/drivers/staging/rtl8192u/dot11d.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef __INC_DOT11D_H -#define __INC_DOT11D_H - -#include "ieee80211/ieee80211.h" - - -typedef struct _CHNL_TXPOWER_TRIPLE { - u8 FirstChnl; - u8 NumChnls; - u8 MaxTxPowerInDbm; -} CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; - -typedef enum _DOT11D_STATE { - DOT11D_STATE_NONE = 0, - DOT11D_STATE_LEARNED, - DOT11D_STATE_DONE, -} DOT11D_STATE; - -typedef struct _RT_DOT11D_INFO { - /* DECLARE_RT_OBJECT(RT_DOT11D_INFO); */ - - bool bEnabled; /* dot11MultiDomainCapabilityEnabled */ - - u16 CountryIeLen; /* > 0 if CountryIeBuf[] contains valid country information element. */ - u8 CountryIeBuf[MAX_IE_LEN]; - u8 CountryIeSrcAddr[6]; /* Source AP of the country IE. */ - u8 CountryIeWatchdog; - - u8 channel_map[MAX_CHANNEL_NUMBER+1]; /* !Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) */ - u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; - - DOT11D_STATE State; -} RT_DOT11D_INFO, *PRT_DOT11D_INFO; -#define eqMacAddr(a, b) (((a)[0] == (b)[0] && \ - (a)[1] == (b)[1] && (a)[2] == (b)[2] && (a)[3] == (b)[3] && \ - (a)[4] == (b)[4] && (a)[5] == (b)[5]) ? 1 : 0) -#define cpMacAddr(des, src) ((des)[0] = (src)[0], \ - (des)[1] = (src)[1], (des)[2] = (src)[2], \ - (des)[3] = (src)[3], (des)[4] = (src)[4], \ - (des)[5] = (src)[5]) -#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) - -#define IS_DOT11D_ENABLE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->bEnabled) -#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) - -#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) -#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) - -#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \ - (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \ - FALSE : \ - (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) - -#define CIE_WATCHDOG_TH 1 -#define GET_CIE_WATCHDOG(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog) -#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 -#define UPDATE_CIE_WATCHDOG(__pIeeeDev) (++GET_CIE_WATCHDOG(__pIeeeDev)) - -#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) - - -void -Dot11d_Init( - struct ieee80211_device *dev - ); - -void -Dot11d_Reset( - struct ieee80211_device *dev - ); - -void -Dot11d_UpdateCountryIe( - struct ieee80211_device *dev, - u8 *pTaddr, - u16 CoutryIeLen, - u8 *pCoutryIe - ); - -u8 -DOT11D_GetMaxTxPwrInDbm( - struct ieee80211_device *dev, - u8 Channel - ); - -void -DOT11D_ScanComplete( - struct ieee80211_device *dev - ); - -int IsLegalChannel( - struct ieee80211_device *dev, - u8 channel -); - -int ToLegalChannel( - struct ieee80211_device *dev, - u8 channel -); -#endif /* #ifndef __INC_DOT11D_H */ diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.h b/drivers/staging/rtl8192u/ieee80211/dot11d.h index 6aa8c15eba39..bd75e29adc2c 100644 --- a/drivers/staging/rtl8192u/ieee80211/dot11d.h +++ b/drivers/staging/rtl8192u/ieee80211/dot11d.h @@ -4,42 +4,43 @@ #include "ieee80211.h" -//#define DOT11D_MAX_CHNL_NUM 83 - typedef struct _CHNL_TXPOWER_TRIPLE { u8 FirstChnl; u8 NumChnls; u8 MaxTxPowerInDbm; -}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; +} CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; typedef enum _DOT11D_STATE { DOT11D_STATE_NONE = 0, DOT11D_STATE_LEARNED, DOT11D_STATE_DONE, -}DOT11D_STATE; +} DOT11D_STATE; typedef struct _RT_DOT11D_INFO { - //DECLARE_RT_OBJECT(RT_DOT11D_INFO); + /* DECLARE_RT_OBJECT(RT_DOT11D_INFO); */ - bool bEnabled; // dot11MultiDomainCapabilityEnabled + bool bEnabled; /* dot11MultiDomainCapabilityEnabled */ - u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element. + u16 CountryIeLen; /* > 0 if CountryIeBuf[] contains valid country information element. */ u8 CountryIeBuf[MAX_IE_LEN]; - u8 CountryIeSrcAddr[6]; // Source AP of the country IE. + u8 CountryIeSrcAddr[6]; /* Source AP of the country IE. */ u8 CountryIeWatchdog; - u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) - //u8 ChnlListLen; // #Bytes valid in ChnlList[]. - //u8 ChnlList[DOT11D_MAX_CHNL_NUM]; + u8 channel_map[MAX_CHANNEL_NUMBER+1]; /* !Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) */ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; DOT11D_STATE State; -}RT_DOT11D_INFO, *PRT_DOT11D_INFO; -#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) -#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) +} RT_DOT11D_INFO, *PRT_DOT11D_INFO; +#define eqMacAddr(a, b) (((a)[0] == (b)[0] && \ + (a)[1] == (b)[1] && (a)[2] == (b)[2] && (a)[3] == (b)[3] && \ + (a)[4] == (b)[4] && (a)[5] == (b)[5]) ? 1 : 0) +#define cpMacAddr(des, src) ((des)[0] = (src)[0], \ + (des)[1] = (src)[1], (des)[2] = (src)[2], \ + (des)[3] = (src)[3], (des)[4] = (src)[4], \ + (des)[5] = (src)[5]) #define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) -#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled +#define IS_DOT11D_ENABLE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->bEnabled) #define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) #define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) @@ -51,9 +52,9 @@ typedef struct _RT_DOT11D_INFO { (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) #define CIE_WATCHDOG_TH 1 -#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog +#define GET_CIE_WATCHDOG(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog) #define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 -#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev) +#define UPDATE_CIE_WATCHDOG(__pIeeeDev) (++GET_CIE_WATCHDOG(__pIeeeDev)) #define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) @@ -72,7 +73,7 @@ void Dot11d_UpdateCountryIe( struct ieee80211_device *dev, u8 *pTaddr, - u16 CoutryIeLen, + u16 CoutryIeLen, u8 *pCoutryIe ); @@ -96,4 +97,4 @@ int ToLegalChannel( struct ieee80211_device *dev, u8 channel ); -#endif // #ifndef __INC_DOT11D_H +#endif /* #ifndef __INC_DOT11D_H */ diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c index 434c43127183..4b036a8db5a1 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c @@ -241,7 +241,7 @@ static int debug = \ //IEEE80211_DL_DATA | IEEE80211_DL_ERR //awayls open this flags to show error out ; -struct proc_dir_entry *ieee80211_proc; +static struct proc_dir_entry *ieee80211_proc; static int show_debug_level(struct seq_file *m, void *v) { diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index 59900bfa1c18..e730ed64c0fe 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -2166,7 +2166,8 @@ static inline u8 ieee80211_SignalStrengthTranslate( return RetSS; } -long ieee80211_translate_todbm(u8 signal_strength_index )// 0-100 index. +/* 0-100 index */ +static long ieee80211_translate_todbm(u8 signal_strength_index) { long signal_power; // in dBm. diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c index a7bcc64ff226..157b2d7466e5 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c @@ -237,8 +237,8 @@ void ieee80211_txb_free(struct ieee80211_txb *txb) { kfree(txb); } -struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, - int gfp_mask) +static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, + gfp_t gfp_mask) { struct ieee80211_txb *txb; int i; @@ -303,7 +303,8 @@ ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network) } #define SN_LESS(a, b) (((a-b)&0x800)!=0) -void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee, struct sk_buff *skb, cb_desc *tcb_desc) +static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee, + struct sk_buff *skb, cb_desc *tcb_desc) { PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; PTX_TS_RECORD pTxTs = NULL; @@ -412,7 +413,8 @@ ieee80211_query_HTCapShortGI(struct ieee80211_device *ieee, cb_desc *tcb_desc) tcb_desc->bUseShortGI = true; } -void ieee80211_query_BandwidthMode(struct ieee80211_device *ieee, cb_desc *tcb_desc) +static void ieee80211_query_BandwidthMode(struct ieee80211_device *ieee, + cb_desc *tcb_desc) { PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; @@ -432,7 +434,9 @@ void ieee80211_query_BandwidthMode(struct ieee80211_device *ieee, cb_desc *tcb_d return; } -void ieee80211_query_protectionmode(struct ieee80211_device *ieee, cb_desc *tcb_desc, struct sk_buff *skb) +static void ieee80211_query_protectionmode(struct ieee80211_device *ieee, + cb_desc *tcb_desc, + struct sk_buff *skb) { // Common Settings tcb_desc->bRTSSTBC = false; @@ -543,7 +547,8 @@ NO_PROTECTION: } -void ieee80211_txrate_selectmode(struct ieee80211_device *ieee, cb_desc *tcb_desc) +static void ieee80211_txrate_selectmode(struct ieee80211_device *ieee, + cb_desc *tcb_desc) { #ifdef TO_DO_LIST if(!IsDataFrame(pFrame)) @@ -573,7 +578,8 @@ void ieee80211_txrate_selectmode(struct ieee80211_device *ieee, cb_desc *tcb_des } } -void ieee80211_query_seqnum(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *dst) +static void ieee80211_query_seqnum(struct ieee80211_device *ieee, + struct sk_buff *skb, u8 *dst) { if (is_multicast_ether_addr(dst)) return; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c index db0db9347487..3684da340bd4 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c @@ -251,7 +251,8 @@ static struct sk_buff *ieee80211_DELBA( * output: none * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does ********************************************************************************************************************/ -void ieee80211_send_ADDBAReq(struct ieee80211_device *ieee, u8 *dst, PBA_RECORD pBA) +static void ieee80211_send_ADDBAReq(struct ieee80211_device *ieee, + u8 *dst, PBA_RECORD pBA) { struct sk_buff *skb = NULL; skb = ieee80211_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); //construct ACT_ADDBAREQ frames so set statuscode zero. @@ -278,7 +279,8 @@ void ieee80211_send_ADDBAReq(struct ieee80211_device *ieee, u8 *dst, PBA_RECORD * output: none * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does ********************************************************************************************************************/ -void ieee80211_send_ADDBARsp(struct ieee80211_device *ieee, u8 *dst, PBA_RECORD pBA, u16 StatusCode) +static void ieee80211_send_ADDBARsp(struct ieee80211_device *ieee, u8 *dst, + PBA_RECORD pBA, u16 StatusCode) { struct sk_buff *skb = NULL; skb = ieee80211_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); //construct ACT_ADDBARSP frames diff --git a/drivers/staging/rtl8192u/ieee80211_crypt.h b/drivers/staging/rtl8192u/ieee80211_crypt.h deleted file mode 100644 index 0b4ea431982d..000000000000 --- a/drivers/staging/rtl8192u/ieee80211_crypt.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Original code based on Host AP (software wireless LAN access point) driver - * for Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * <jkmaline@cc.hut.fi> - * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> - * - * Adaption to a generic IEEE 802.11 stack by James Ketrenos - * <jketreno@linux.intel.com> - * - * Copyright (c) 2004, Intel Corporation - * - * 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. See README and COPYING for - * more details. - */ - -/* - * This file defines the interface to the ieee80211 crypto module. - */ -#ifndef IEEE80211_CRYPT_H -#define IEEE80211_CRYPT_H - -#include <linux/skbuff.h> - -struct ieee80211_crypto_ops { - const char *name; - - /* init new crypto context (e.g., allocate private data space, - * select IV, etc.); returns NULL on failure or pointer to allocated - * private data on success */ - void * (*init)(int keyidx); - - /* deinitialize crypto context and free allocated private data */ - void (*deinit)(void *priv); - - /* encrypt/decrypt return < 0 on error or >= 0 on success. The return - * value from decrypt_mpdu is passed as the keyidx value for - * decrypt_msdu. skb must have enough head and tail room for the - * encryption; if not, error will be returned; these functions are - * called for all MPDUs (i.e., fragments). - */ - int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); - - /* These functions are called for full MSDUs, i.e. full frames. - * These can be NULL if full MSDU operations are not needed. */ - int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, - void *priv); - - int (*set_key)(void *key, int len, u8 *seq, void *priv); - int (*get_key)(void *key, int len, u8 *seq, void *priv); - - /* procfs handler for printing out key information and possible - * statistics */ - char * (*print_stats)(char *p, void *priv); - - /* maximum number of bytes added by encryption; encrypt buf is - * allocated with extra_prefix_len bytes, copy of in_buf, and - * extra_postfix_len; encrypt need not use all this space, but - * the result must start at the beginning of the buffer and correct - * length must be returned */ - int extra_prefix_len, extra_postfix_len; - - struct module *owner; -}; - -struct ieee80211_crypt_data { - struct list_head list; /* delayed deletion list */ - struct ieee80211_crypto_ops *ops; - void *priv; - atomic_t refcnt; -}; - -int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); -int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); -struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name); -void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); -void ieee80211_crypt_deinit_handler(unsigned long); -void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, - struct ieee80211_crypt_data **crypt); - -#endif diff --git a/drivers/staging/rtl8192u/r8180_pm.c b/drivers/staging/rtl8192u/r8180_pm.c deleted file mode 100644 index 999968d41720..000000000000 --- a/drivers/staging/rtl8192u/r8180_pm.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - Power management interface routines. - Written by Mariusz Matuszek. - This code is currently just a placeholder for later work and - does not do anything useful. - - This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com> - Released under the terms of GPL (General Public Licence) -*/ - -#ifdef CONFIG_RTL8180_PM - - -#include "r8180_hw.h" -#include "r8180_pm.h" - -int rtl8180_save_state (struct pci_dev *dev, u32 state) -{ - printk(KERN_NOTICE "r8180 save state call (state %u).\n", state); - return(-EAGAIN); -} - - -int rtl8180_suspend (struct pci_dev *dev, u32 state) -{ - printk(KERN_NOTICE "r8180 suspend call (state %u).\n", state); - return(-EAGAIN); -} - - -int rtl8180_resume (struct pci_dev *dev) -{ - printk(KERN_NOTICE "r8180 resume call.\n"); - return(-EAGAIN); -} - - -int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable) -{ - printk(KERN_NOTICE "r8180 enable wake call (state %u, enable %d).\n", - state, enable); - return(-EAGAIN); -} - - - -#endif //CONFIG_RTL8180_PM diff --git a/drivers/staging/rtl8192u/r8180_pm.h b/drivers/staging/rtl8192u/r8180_pm.h deleted file mode 100644 index 4be63da0b781..000000000000 --- a/drivers/staging/rtl8192u/r8180_pm.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - Power management interface routines. - Written by Mariusz Matuszek. - This code is currently just a placeholder for later work and - does not do anything useful. - - This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com> - Released under the terms of GPL (General Public Licence) - -*/ - -#ifdef CONFIG_RTL8180_PM - -#ifndef R8180_PM_H -#define R8180_PM_H - -#include <linux/types.h> -#include <linux/pci.h> - -int rtl8180_save_state (struct pci_dev *dev, u32 state); -int rtl8180_suspend (struct pci_dev *dev, u32 state); -int rtl8180_resume (struct pci_dev *dev); -int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable); - -#endif //R8180_PM_H - -#endif // CONFIG_RTL8180_PM diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.h b/drivers/staging/rtl8192u/r8190_rtl8256.h index 592e7807fa42..fa6dd37d85e6 100644 --- a/drivers/staging/rtl8192u/r8190_rtl8256.h +++ b/drivers/staging/rtl8192u/r8190_rtl8256.h @@ -13,11 +13,7 @@ #ifndef RTL8225H #define RTL8225H -#ifdef RTL8190P -#define RTL819X_TOTAL_RF_PATH 4 //for 90P -#else #define RTL819X_TOTAL_RF_PATH 2 //for 8192U -#endif extern void PHY_SetRF8256Bandwidth(struct net_device *dev , HT_CHANNEL_WIDTH Bandwidth); extern void PHY_RF8256_Config(struct net_device *dev); extern void phy_RF8256_Config_ParaFile(struct net_device *dev); diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index b484ee128c13..ad3bc567d35a 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -409,15 +409,11 @@ typedef struct rx_drvinfo_819x_usb { #define USB_HWDESC_HEADER_LEN sizeof(tx_desc_819x_usb) #define TX_PACKET_SHIFT_BYTES (USB_HWDESC_HEADER_LEN + sizeof(tx_fwinfo_819x_usb)) #define MAX_FRAGMENT_COUNT 8 -#ifdef RTL8192U #ifdef USB_TX_DRIVER_AGGREGATION_ENABLE #define MAX_TRANSMIT_BUFFER_SIZE 32000 #else #define MAX_TRANSMIT_BUFFER_SIZE 8000 #endif -#else -#define MAX_TRANSMIT_BUFFER_SIZE (1600+(MAX_802_11_HEADER_LENGTH+ENCRYPTION_MAX_OVERHEAD)*MAX_FRAGMENT_COUNT) -#endif #ifdef USB_TX_DRIVER_AGGREGATION_ENABLE #define TX_PACKET_DRVAGGR_SUBFRAME_SHIFT_BYTES (sizeof(tx_desc_819x_usb_aggr_subframe) + sizeof(tx_fwinfo_819x_usb)) #endif @@ -1158,14 +1154,6 @@ typedef enum { NIC_8192E = 3, } nic_t; - -#ifdef JOHN_HWSEC -struct ssid_thread { - struct net_device *dev; - u8 name[IW_ESSID_MAX_SIZE + 1]; -}; -#endif - bool init_firmware(struct net_device *dev); short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb); short rtl8192_tx(struct net_device *dev, struct sk_buff *skb); diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index cd0946db025c..63a4cdf1dc04 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -392,7 +392,7 @@ int read_nic_word(struct net_device *dev, int indx, u16 *data) return 0; } -int read_nic_word_E(struct net_device *dev, int indx, u16 *data) +static int read_nic_word_E(struct net_device *dev, int indx, u16 *data) { int status; struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); @@ -585,7 +585,7 @@ static int proc_get_stats_rx(struct seq_file *m, void *v) return 0; } -void rtl8192_proc_module_init(void) +static void rtl8192_proc_module_init(void) { RT_TRACE(COMP_INIT, "Initializing proc filesystem"); rtl8192_proc = proc_mkdir(RTL819xU_MODULE_NAME, init_net.proc_net); @@ -631,7 +631,7 @@ static const struct rtl8192_proc_file rtl8192_proc_files[] = { { "" } }; -void rtl8192_proc_init_one(struct net_device *dev) +static void rtl8192_proc_init_one(struct net_device *dev) { const struct rtl8192_proc_file *f; struct proc_dir_entry *dir; @@ -656,7 +656,7 @@ void rtl8192_proc_init_one(struct net_device *dev) } } -void rtl8192_proc_remove_one(struct net_device *dev) +static void rtl8192_proc_remove_one(struct net_device *dev) { remove_proc_subtree(dev->name, rtl8192_proc); } @@ -755,7 +755,7 @@ void rtl8192_set_chan(struct net_device *dev, short ch) static void rtl8192_rx_isr(struct urb *urb); -u32 get_rxpacket_shiftbytes_819xusb(struct ieee80211_rx_stats *pstats) +static u32 get_rxpacket_shiftbytes_819xusb(struct ieee80211_rx_stats *pstats) { #ifdef USB_RX_AGGREGATION_SUPPORT @@ -998,8 +998,8 @@ static void rtl8192_rx_isr(struct urb *urb) netdev_err(dev, "can not submit rxurb, err is %x, URB status is %x\n", err, urb->status); } -u32 rtl819xusb_rx_command_packet(struct net_device *dev, - struct ieee80211_rx_stats *pstats) +static u32 rtl819xusb_rx_command_packet(struct net_device *dev, + struct ieee80211_rx_stats *pstats) { u32 status; @@ -1609,13 +1609,6 @@ short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb) #else idx_pipe = 0x04; #endif -#ifdef JOHN_DUMP_TXDESC - int i; - printk("<Tx descriptor>--rate %x---", rate); - for (i = 0; i < 8; i++) - printk("%8x ", tx[i]); - printk("\n"); -#endif usb_fill_bulk_urb(tx_urb, priv->udev, usb_sndbulkpipe(priv->udev, idx_pipe), skb->data, skb->len, rtl8192_tx_isr, skb); @@ -1636,7 +1629,7 @@ short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb) * * \param QUEUEID Software Queue */ -u8 MapHwQueueToFirmwareQueue(u8 QueueID) +static u8 MapHwQueueToFirmwareQueue(u8 QueueID) { u8 QueueSelect = 0x0; //defualt set to @@ -1723,7 +1716,7 @@ u8 MRateToHwRate8190Pci(u8 rate) } -u8 QueryIsShort(u8 TxHT, u8 TxRate, cb_desc *tcb_desc) +static u8 QueryIsShort(u8 TxHT, u8 TxRate, cb_desc *tcb_desc) { u8 tmp_Short; @@ -1934,7 +1927,7 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) } } -short rtl8192_usb_initendpoints(struct net_device *dev) +static short rtl8192_usb_initendpoints(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -1992,7 +1985,7 @@ short rtl8192_usb_initendpoints(struct net_device *dev) } #ifdef THOMAS_BEACON -void rtl8192_usb_deleteendpoints(struct net_device *dev) +static void rtl8192_usb_deleteendpoints(struct net_device *dev) { int i; struct r8192_priv *priv = ieee80211_priv(dev); @@ -2009,7 +2002,7 @@ void rtl8192_usb_deleteendpoints(struct net_device *dev) priv->oldaddr = NULL; if (priv->pp_rxskb) { kfree(priv->pp_rxskb); - priv->pp_rxskb = 0; + priv->pp_rxskb = NULL; } } #else @@ -2292,7 +2285,7 @@ void rtl8192_update_ratr_table(struct net_device *dev) static u8 ccmp_ie[4] = {0x00, 0x50, 0xf2, 0x04}; static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04}; -bool GetNmodeSupportBySecCfg8192(struct net_device *dev) +static bool GetNmodeSupportBySecCfg8192(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee80211; @@ -3167,7 +3160,7 @@ static struct net_device_stats *rtl8192_stats(struct net_device *dev) return &priv->ieee80211->stats; } -bool HalTxCheckStuck819xUsb(struct net_device *dev) +static bool HalTxCheckStuck819xUsb(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); u16 RegTxCounter; @@ -3217,7 +3210,7 @@ RESET_TYPE TxCheckStuck(struct net_device *dev) return RESET_TYPE_NORESET; } -bool HalRxCheckStuck819xUsb(struct net_device *dev) +static bool HalRxCheckStuck819xUsb(struct net_device *dev) { u16 RegRxCounter; struct r8192_priv *priv = ieee80211_priv(dev); @@ -3259,7 +3252,7 @@ bool HalRxCheckStuck819xUsb(struct net_device *dev) return bStuck; } -RESET_TYPE RxCheckStuck(struct net_device *dev) +static RESET_TYPE RxCheckStuck(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); bool bRxCheck = FALSE; @@ -3859,15 +3852,6 @@ int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } } } -#ifdef JOHN_HWSEC_DEBUG - //john's test 0711 - printk("@@ wrq->u pointer = "); - for (i = 0; i < wrq->u.data.length; i++) { - if (i%10 == 0) printk("\n"); - printk("%8x|", ((u32 *)wrq->u.data.pointer)[i]); - } - printk("\n"); -#endif /*JOHN_HWSEC_DEBUG*/ ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data); break; @@ -3952,7 +3936,8 @@ u8 HwRateToMRate90(bool bIsHT, u8 rate) * Return: * None */ -void UpdateRxPktTimeStamp8190(struct net_device *dev, struct ieee80211_rx_stats *stats) +static void UpdateRxPktTimeStamp8190(struct net_device *dev, + struct ieee80211_rx_stats *stats) { struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); @@ -4209,7 +4194,7 @@ static u8 rtl819x_evm_dbtopercentage(char value) // We want good-looking for signal strength/quality // 2007/7/19 01:09, by cosa. // -long rtl819x_signal_scale_mapping(long currsig) +static long rtl819x_signal_scale_mapping(long currsig) { long retsig; @@ -4478,9 +4463,9 @@ void rtl8192_record_rxdesc_forlateruse(struct ieee80211_rx_stats *psrc_stats, } -void TranslateRxSignalStuff819xUsb(struct sk_buff *skb, - struct ieee80211_rx_stats *pstats, - rx_drvinfo_819x_usb *pdrvinfo) +static void TranslateRxSignalStuff819xUsb(struct sk_buff *skb, + struct ieee80211_rx_stats *pstats, + rx_drvinfo_819x_usb *pdrvinfo) { // TODO: We must only check packet for current MAC address. Not finish rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; @@ -4549,8 +4534,9 @@ void TranslateRxSignalStuff819xUsb(struct sk_buff *skb, * Return: * None */ -void UpdateReceivedRateHistogramStatistics8190(struct net_device *dev, - struct ieee80211_rx_stats *stats) +static void +UpdateReceivedRateHistogramStatistics8190(struct net_device *dev, + struct ieee80211_rx_stats *stats) { struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); u32 rcvType = 1; //0: Total, 1:OK, 2:CRC, 3:ICV @@ -4614,7 +4600,9 @@ void UpdateReceivedRateHistogramStatistics8190(struct net_device *dev, } -void query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats, bool bIsRxAggrSubframe) +static void query_rxdesc_status(struct sk_buff *skb, + struct ieee80211_rx_stats *stats, + bool bIsRxAggrSubframe) { rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; struct net_device *dev = info->dev; @@ -4930,7 +4918,8 @@ void rtl819xusb_process_received_packet(struct net_device *dev, } -void query_rx_cmdpkt_desc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats) +static void query_rx_cmdpkt_desc_status(struct sk_buff *skb, + struct ieee80211_rx_stats *stats) { rx_desc_819x_usb *desc = (rx_desc_819x_usb *)skb->data; diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c index a6e4c37d9c78..41fb67b7337d 100644 --- a/drivers/staging/rtl8192u/r8192U_dm.c +++ b/drivers/staging/rtl8192u/r8192U_dm.c @@ -100,14 +100,6 @@ static void dm_check_txpower_tracking(struct net_device *dev); //static void dm_txpower_reset_recovery(struct net_device *dev); -// DM --> BB init gain restore -#ifndef RTL8192U -static void dm_bb_initialgain_restore(struct net_device *dev); - - -// DM --> BB init gain backup -static void dm_bb_initialgain_backup(struct net_device *dev); -#endif // DM --> Dynamic Init Gain by RSSI static void dm_dig_init(struct net_device *dev); static void dm_ctrl_initgain_byrssi(struct net_device *dev); @@ -122,12 +114,7 @@ static void dm_init_ctstoself(struct net_device *dev); // DM --> EDCA turbo mode control static void dm_check_edca_turbo(struct net_device *dev); -// DM --> HW RF control -static void dm_check_rfctrl_gpio(struct net_device *dev); - -#ifndef RTL8190P //static void dm_gpio_change_rf(struct net_device *dev); -#endif // DM --> Check PBC static void dm_check_pbc_gpio(struct net_device *dev); @@ -269,7 +256,6 @@ extern void hal_dm_watchdog(struct net_device *dev) dm_ctrl_initgain_byrssi(dev); dm_check_edca_turbo(dev); dm_bandwidth_autoswitch(dev); - dm_check_rfctrl_gpio(dev); dm_check_rx_path_selection(dev); dm_check_fsync(dev); @@ -620,16 +606,11 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING; tx_cmd.Length = 4; tx_cmd.Value = Value; -#ifdef RTL8192U rtStatus = SendTxCommandPacket(dev, &tx_cmd, 12); if (rtStatus == RT_STATUS_FAILURE) { RT_TRACE(COMP_POWER_TRACKING, "Set configuration with tx cmd queue fail!\n"); } -#else - cmpk_message_handle_tx(dev, (u8 *)&tx_cmd, - DESC_PACKET_TYPE_INIT, sizeof(DCMD_TXCMD_T)); -#endif mdelay(1); //DbgPrint("hi, vivi, strange\n"); for(i = 0;i <= 30; i++) @@ -641,11 +622,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) mdelay(1); continue; } -#ifdef RTL8190P - read_nic_word(dev, 0x1bc, &Avg_TSSI_Meas); -#else read_nic_word(dev, 0x13c, &Avg_TSSI_Meas); -#endif if(Avg_TSSI_Meas == 0) { write_nic_byte(dev, 0x1ba, 0); @@ -654,14 +631,10 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) for(k = 0;k < 5; k++) { -#ifdef RTL8190P - read_nic_byte(dev, 0x1d8+k, &tmp_report[k]); -#else if(k !=4) read_nic_byte(dev, 0x134+k, &tmp_report[k]); else read_nic_byte(dev, 0x13e, &tmp_report[k]); -#endif RT_TRACE(COMP_POWER_TRACKING, "TSSI_report_value = %d\n", tmp_report[k]); } @@ -708,10 +681,6 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n"); RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex); RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real); -#ifdef RTL8190P - RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex = %d\n", priv->rfc_txpowertrackingindex); - RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex_real = %d\n", priv->rfc_txpowertrackingindex_real); -#endif RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference); RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation); return; @@ -720,11 +689,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) { if(Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK) { - if((priv->rfa_txpowertrackingindex > 0) -#ifdef RTL8190P - &&(priv->rfc_txpowertrackingindex > 0) -#endif - ) + if (priv->rfa_txpowertrackingindex > 0) { priv->rfa_txpowertrackingindex--; if(priv->rfa_txpowertrackingindex_real > 4) @@ -732,33 +697,16 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) priv->rfa_txpowertrackingindex_real--; rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); } -#ifdef RTL8190P - priv->rfc_txpowertrackingindex--; - if(priv->rfc_txpowertrackingindex_real > 4) - { - priv->rfc_txpowertrackingindex_real--; - rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); - } -#endif } } else { - if((priv->rfa_txpowertrackingindex < 36) -#ifdef RTL8190P - &&(priv->rfc_txpowertrackingindex < 36) -#endif - ) + if (priv->rfa_txpowertrackingindex < 36) { priv->rfa_txpowertrackingindex++; priv->rfa_txpowertrackingindex_real++; rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); -#ifdef RTL8190P - priv->rfc_txpowertrackingindex++; - priv->rfc_txpowertrackingindex_real++; - rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); -#endif } } priv->cck_present_attentuation_difference @@ -788,10 +736,6 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) } RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex); RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real); -#ifdef RTL8190P - RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex = %d\n", priv->rfc_txpowertrackingindex); - RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex_real = %d\n", priv->rfc_txpowertrackingindex_real); -#endif RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference); RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation); @@ -937,14 +881,10 @@ extern void dm_txpower_trackingcallback(struct work_struct *work) struct r8192_priv *priv = container_of(dwork,struct r8192_priv,txpower_tracking_wq); struct net_device *dev = priv->ieee80211->dev; -#ifdef RTL8190P - dm_TXPowerTrackingCallback_TSSI(dev); -#else if(priv->bDcut == TRUE) dm_TXPowerTrackingCallback_TSSI(dev); else dm_TXPowerTrackingCallback_ThermalMeter(dev); -#endif } @@ -1472,14 +1412,10 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev) void dm_initialize_txpower_tracking(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); -#ifdef RTL8190P - dm_InitializeTXPowerTracking_TSSI(dev); -#else if(priv->bDcut == TRUE) dm_InitializeTXPowerTracking_TSSI(dev); else dm_InitializeTXPowerTracking_ThermalMeter(dev); -#endif }// dm_InitializeTXPowerTracking @@ -1677,14 +1613,10 @@ extern void dm_cck_txpower_adjust( { // dm_CCKTxPowerAdjust struct r8192_priv *priv = ieee80211_priv(dev); -#ifdef RTL8190P - dm_CCKTxPowerAdjust_TSSI(dev, binch14); -#else if(priv->bDcut == TRUE) dm_CCKTxPowerAdjust_TSSI(dev, binch14); else dm_CCKTxPowerAdjust_ThermalMeter(dev, binch14); -#endif } @@ -2194,11 +2126,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( { /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); - #else - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); - #endif + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) write_nic_byte(pAdapter, rOFDM0_RxDetector1, 0x40); */ @@ -2265,11 +2193,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( { /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); - #else - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); - #endif + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); /* else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); @@ -2342,11 +2266,7 @@ static void dm_ctrl_initgain_byrssi_highpwr( // 3.1 Higher PD_TH for OFDM for high power state. if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) { - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); - #else - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); - #endif + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); @@ -2370,11 +2290,7 @@ static void dm_ctrl_initgain_byrssi_highpwr( // 3.2 Recover PD_TH for OFDM for normal power region. if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) { - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); - #else - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); - #endif + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); */ @@ -2516,11 +2432,7 @@ static void dm_pd_th( { /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); - #else - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); - #endif + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); */ @@ -2535,11 +2447,7 @@ static void dm_pd_th( { /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); - #else - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); - #endif + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); */ @@ -2552,11 +2460,7 @@ static void dm_pd_th( // Higher PD_TH for OFDM for high power state. if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) { - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); - #else - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); - #endif + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); */ @@ -2823,44 +2727,6 @@ static void dm_ctstoself(struct net_device *dev) } } - -/*----------------------------------------------------------------------------- - * Function: dm_check_rfctrl_gpio() - * - * Overview: Copy 8187B template for 9xseries. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 05/28/2008 amy Create Version 0 porting from windows code. - * - *---------------------------------------------------------------------------*/ -static void dm_check_rfctrl_gpio(struct net_device *dev) -{ - //struct r8192_priv *priv = ieee80211_priv(dev); - - // Work around for DTM test, we will not enable HW - radio on/off because r/w - // page 1 register before extra bus is enabled causing system failures when resuming - // from S4. 20080218, Emily - - // Stop to execute workitem to prevent S3/S4 bug. -#ifdef RTL8190P - return; -#endif -#ifdef RTL8192U - return; -#endif -#ifdef RTL8192E - queue_delayed_work(priv->priv_wq,&priv->gpio_change_rf_wq,0); -#endif - -} /* dm_CheckRfCtrlGPIO */ - /*----------------------------------------------------------------------------- * Function: dm_check_pbc_gpio() * @@ -2879,7 +2745,6 @@ static void dm_check_rfctrl_gpio(struct net_device *dev) *---------------------------------------------------------------------------*/ static void dm_check_pbc_gpio(struct net_device *dev) { -#ifdef RTL8192U struct r8192_priv *priv = ieee80211_priv(dev); u8 tmp1byte; @@ -2895,83 +2760,9 @@ static void dm_check_pbc_gpio(struct net_device *dev) RT_TRACE(COMP_IO, "CheckPbcGPIO - PBC is pressed\n"); priv->bpbc_pressed = true; } -#endif } -#ifdef RTL8192E - -/*----------------------------------------------------------------------------- - * Function: dm_GPIOChangeRF - * Overview: PCI will not support workitem call back HW radio on-off control. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 02/21/2008 MHC Create Version 0. - * - *---------------------------------------------------------------------------*/ -extern void dm_gpio_change_rf_callback(struct work_struct *work) -{ - struct delayed_work *dwork = container_of(work,struct delayed_work,work); - struct r8192_priv *priv = container_of(dwork,struct r8192_priv,gpio_change_rf_wq); - struct net_device *dev = priv->ieee80211->dev; - u8 tmp1byte; - RT_RF_POWER_STATE eRfPowerStateToSet; - bool bActuallySet = false; - - do{ - bActuallySet=false; - - if(!priv->up) - { - RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF),"dm_gpio_change_rf_callback(): Callback function breaks out!!\n"); - } - else - { - // 0x108 GPIO input register is read only - //set 0x108 B1= 1: RF-ON; 0: RF-OFF. - read_nic_byte(dev, GPI, &tmp1byte); - - eRfPowerStateToSet = (tmp1byte&BIT1) ? eRfOn : eRfOff; - - if((priv->bHwRadioOff == true) && (eRfPowerStateToSet == eRfOn)) - { - RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio ON\n"); - - priv->bHwRadioOff = false; - bActuallySet = true; - } - else if ((priv->bHwRadioOff == false) && (eRfPowerStateToSet == eRfOff)) - { - RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio OFF\n"); - priv->bHwRadioOff = true; - bActuallySet = true; - } - - if(bActuallySet) - { - #ifdef TO_DO - MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); - //DrvIFIndicateCurrentPhyStatus(pAdapter); - #endif - } - else - { - msleep(2000); - } - - } - }while(TRUE) - -} /* dm_GPIOChangeRF */ - -#endif /*----------------------------------------------------------------------------- * Function: DM_RFPathCheckWorkItemCallBack() * @@ -3329,11 +3120,7 @@ static void dm_init_fsync (struct net_device *dev) priv->ieee80211->fsync_time_interval = 500; priv->ieee80211->fsync_rate_bitmap = 0x0f000800; priv->ieee80211->fsync_rssi_threshold = 30; -#ifdef RTL8190P - priv->ieee80211->bfsync_enable = true; -#else priv->ieee80211->bfsync_enable = false; -#endif priv->ieee80211->fsync_multiple_timeinterval = 3; priv->ieee80211->fsync_firstdiff_ratethreshold= 100; priv->ieee80211->fsync_seconddiff_ratethreshold= 200; @@ -3416,20 +3203,12 @@ extern void dm_fsync_timer_callback(unsigned long data) priv->bswitch_fsync = !priv->bswitch_fsync; if(priv->bswitch_fsync) { - #ifdef RTL8190P - write_nic_byte(dev, 0xC36, 0x00); - #else write_nic_byte(dev,0xC36, 0x1c); - #endif write_nic_byte(dev, 0xC3e, 0x90); } else { - #ifdef RTL8190P - write_nic_byte(dev, 0xC36, 0x40); - #else write_nic_byte(dev, 0xC36, 0x5c); - #endif write_nic_byte(dev, 0xC3e, 0x96); } } @@ -3438,11 +3217,7 @@ extern void dm_fsync_timer_callback(unsigned long data) if(priv->bswitch_fsync) { priv->bswitch_fsync = false; - #ifdef RTL8190P - write_nic_byte(dev, 0xC36, 0x40); - #else write_nic_byte(dev, 0xC36, 0x5c); - #endif write_nic_byte(dev, 0xC3e, 0x96); } } @@ -3465,19 +3240,11 @@ extern void dm_fsync_timer_callback(unsigned long data) if(priv->bswitch_fsync) { priv->bswitch_fsync = false; - #ifdef RTL8190P - write_nic_byte(dev, 0xC36, 0x40); - #else write_nic_byte(dev, 0xC36, 0x5c); - #endif write_nic_byte(dev, 0xC3e, 0x96); } priv->ContinueDiffCount = 0; - #ifdef RTL8190P - write_nic_dword(dev, rOFDM0_RxDetector2, 0x164052cd); - #else write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); - #endif } RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount); RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync); @@ -3502,19 +3269,13 @@ static void dm_EndSWFsync(struct net_device *dev) { priv->bswitch_fsync = false; - #ifdef RTL8190P - write_nic_byte(dev, 0xC36, 0x40); - #else - write_nic_byte(dev, 0xC36, 0x5c); - #endif + write_nic_byte(dev, 0xC36, 0x5c); write_nic_byte(dev, 0xC3e, 0x96); } priv->ContinueDiffCount = 0; -#ifndef RTL8190P write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); -#endif } @@ -3553,9 +3314,7 @@ static void dm_StartSWFsync(struct net_device *dev) priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval); add_timer(&priv->fsync_timer); -#ifndef RTL8190P write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd); -#endif } @@ -3624,11 +3383,7 @@ void dm_check_fsync(struct net_device *dev) { if(reg_c38_State != RegC38_Fsync_AP_BCM) { //For broadcom AP we write different default value - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector3, 0x15); - #else - write_nic_byte(dev, rOFDM0_RxDetector3, 0x95); - #endif + write_nic_byte(dev, rOFDM0_RxDetector3, 0x95); reg_c38_State = RegC38_Fsync_AP_BCM; } @@ -3659,11 +3414,7 @@ void dm_check_fsync(struct net_device *dev) { if(reg_c38_State != RegC38_NonFsync_Other_AP) { - #ifdef RTL8190P - write_nic_byte(dev, rOFDM0_RxDetector3, 0x10); - #else - write_nic_byte(dev, rOFDM0_RxDetector3, 0x90); - #endif + write_nic_byte(dev, rOFDM0_RxDetector3, 0x90); reg_c38_State = RegC38_NonFsync_Other_AP; } @@ -3845,10 +3596,8 @@ static void dm_dynamic_txpower(struct net_device *dev) SetTxPowerLevel8190(Adapter,pHalData->CurrentChannel); #endif -#ifdef RTL8192U rtl8192_phy_setTxPower(dev,priv->ieee80211->current_network.channel); //pHalData->bStartTxCtrlByTPCNFR = FALSE; //Clear th flag of Set TX Power from Sitesurvey -#endif } priv->bLastDTPFlag_High = priv->bDynamicTxHighPower; priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower; @@ -3885,9 +3634,6 @@ static void dm_send_rssi_tofw(struct net_device *dev) tx_cmd.Op = TXCMD_SET_RX_RSSI; tx_cmd.Length = 4; tx_cmd.Value = priv->undecorated_smoothed_pwdb; - - cmpk_message_handle_tx(dev, (u8 *)&tx_cmd, - DESC_PACKET_TYPE_INIT, sizeof(DCMD_TXCMD_T)); } /*---------------------------Define function prototype------------------------*/ diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c index 61f6620213e2..c70af014a316 100644 --- a/drivers/staging/rtl8192u/r8192U_wx.c +++ b/drivers/staging/rtl8192u/r8192U_wx.c @@ -127,156 +127,6 @@ static int r8192_wx_get_power(struct net_device *dev, return ieee80211_wx_get_power(priv->ieee80211,info,wrqu,extra); } -#ifdef JOHN_IOCTL -u16 read_rtl8225(struct net_device *dev, u8 addr); -void write_rtl8225(struct net_device *dev, u8 adr, u16 data); -u32 john_read_rtl8225(struct net_device *dev, u8 adr); -void _write_rtl8225(struct net_device *dev, u8 adr, u16 data); - -static int r8192_wx_read_regs(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = ieee80211_priv(dev); - u8 addr; - u16 data1; - - down(&priv->wx_sem); - - - get_user(addr,(u8 *)wrqu->data.pointer); - data1 = read_rtl8225(dev, addr); - wrqu->data.length = data1; - - up(&priv->wx_sem); - return 0; - -} - -static int r8192_wx_write_regs(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = ieee80211_priv(dev); - u8 addr; - - down(&priv->wx_sem); - - get_user(addr, (u8 *)wrqu->data.pointer); - write_rtl8225(dev, addr, wrqu->data.length); - - up(&priv->wx_sem); - return 0; - -} - -void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data); -u8 rtl8187_read_phy(struct net_device *dev,u8 adr, u32 data); - -static int r8192_wx_read_bb(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = ieee80211_priv(dev); - u8 databb; - - down(&priv->wx_sem); - - databb = rtl8187_read_phy(dev, (u8)wrqu->data.length, 0x00000000); - wrqu->data.length = databb; - - up(&priv->wx_sem); - return 0; -} - -void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data); -static int r8192_wx_write_bb(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = ieee80211_priv(dev); - u8 databb; - - down(&priv->wx_sem); - - get_user(databb, (u8 *)wrqu->data.pointer); - rtl8187_write_phy(dev, wrqu->data.length, databb); - - up(&priv->wx_sem); - return 0; - -} - - -static int r8192_wx_write_nicb(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = ieee80211_priv(dev); - u32 addr; - - down(&priv->wx_sem); - - get_user(addr, (u32 *)wrqu->data.pointer); - write_nic_byte(dev, addr, wrqu->data.length); - - up(&priv->wx_sem); - return 0; - -} -static int r8192_wx_read_nicb(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = ieee80211_priv(dev); - u32 addr; - u16 data1; - - down(&priv->wx_sem); - - get_user(addr,(u32 *)wrqu->data.pointer); - read_nic_byte(dev, addr, &data1); - wrqu->data.length = data1; - - up(&priv->wx_sem); - return 0; -} - -static int r8192_wx_get_ap_status(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; - struct ieee80211_network *target; - int name_len; - - down(&priv->wx_sem); - - //count the length of input ssid - for(name_len=0 ; ((char *)wrqu->data.pointer)[name_len]!='\0' ; name_len++); - - //search for the corresponding info which is received - list_for_each_entry(target, &ieee->network_list, list) { - if ( (target->ssid_len == name_len) && - (strncmp(target->ssid, (char *)wrqu->data.pointer, name_len)==0)){ - if(target->wpa_ie_len>0 || target->rsn_ie_len>0 ) - //set flags=1 to indicate this ap is WPA - wrqu->data.flags = 1; - else wrqu->data.flags = 0; - - - break; - } - } - - up(&priv->wx_sem); - return 0; -} - - - -#endif static int r8192_wx_force_reset(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -1106,46 +956,7 @@ static const struct iw_priv_args r8192_private_args[] = { { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx" - } -#ifdef JOHN_IOCTL - , - { - SIOCIWFIRSTPRIV + 0x3, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readRF" - } - , - { - SIOCIWFIRSTPRIV + 0x4, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeRF" - } - , - { - SIOCIWFIRSTPRIV + 0x5, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readBB" - } - , - { - SIOCIWFIRSTPRIV + 0x6, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeBB" - } - , - { - SIOCIWFIRSTPRIV + 0x7, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readnicb" - } - , - { - SIOCIWFIRSTPRIV + 0x8, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writenicb" - } - , - { - SIOCIWFIRSTPRIV + 0x9, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" - } - -#endif - , + }, { SIOCIWFIRSTPRIV + 0x3, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset" @@ -1163,15 +974,6 @@ static iw_handler r8192_private_handler[] = { // r8192_wx_set_monitor_type, r8192_wx_set_scan_type, r8192_wx_set_rawtx, -#ifdef JOHN_IOCTL - r8192_wx_read_regs, - r8192_wx_write_regs, - r8192_wx_read_bb, - r8192_wx_write_bb, - r8192_wx_read_nicb, - r8192_wx_write_nicb, - r8192_wx_get_ap_status, -#endif //r8192_wx_null, r8192_wx_force_reset, }; diff --git a/drivers/staging/rtl8192u/r819xU_HTType.h b/drivers/staging/rtl8192u/r819xU_HTType.h index 19a7bdd1973a..2cbb8e6584f8 100644 --- a/drivers/staging/rtl8192u/r819xU_HTType.h +++ b/drivers/staging/rtl8192u/r819xU_HTType.h @@ -2,41 +2,36 @@ #define _R819XU_HTTYPE_H_ -//------------------------------------------------------------ -// The HT Capability element is present in beacons, association request, -// reassociation request and probe response frames -//------------------------------------------------------------ - -// -// Operation mode value -// +/*---------------------------------------------------------------------- + * The HT Capability element is present in beacons, association request, + * reassociation request and probe response frames + *----------------------------------------------------------------------*/ + +/* Operation mode value */ #define HT_OPMODE_NO_PROTECT 0 #define HT_OPMODE_OPTIONAL 1 -#define HT_OPMODE_40MHZ_PROTECT 2 +#define HT_OPMODE_40MHZ_PROTECT 2 #define HT_OPMODE_MIXED 3 -// -// MIMO Power Save Settings -// -#define MIMO_PS_STATIC 0 +/* MIMO Power Save Settings */ +#define MIMO_PS_STATIC 0 #define MIMO_PS_DYNAMIC 1 #define MIMO_PS_NOLIMIT 3 -// -// There should be 128 bits to cover all of the MCS rates. However, since -// 8190 does not support too much rates, one integer is quite enough. -// +/* There should be 128 bits to cover all of the MCS rates. However, since + * 8190 does not support too much rates, one integer is quite enough. */ -#define sHTCLng 4 +#define sHTCLng 4 -#define HT_SUPPORTED_MCS_1SS_BITMAP 0x000000ff -#define HT_SUPPORTED_MCS_2SS_BITMAP 0x0000ff00 -#define HT_SUPPORTED_MCS_1SS_2SS_BITMAP HT_MCS_1SS_BITMAP|HT_MCS_1SS_2SS_BITMAP +#define HT_SUPPORTED_MCS_1SS_BITMAP 0x000000ff +#define HT_SUPPORTED_MCS_2SS_BITMAP 0x0000ff00 +#define HT_SUPPORTED_MCS_1SS_2SS_BITMAP \ + (HT_MCS_1SS_BITMAP | HT_MCS_1SS_2SS_BITMAP) -typedef enum _HT_MCS_RATE{ +typedef enum _HT_MCS_RATE { HT_MCS0 = 0x00000001, HT_MCS1 = 0x00000002, HT_MCS2 = 0x00000004, @@ -47,71 +42,67 @@ typedef enum _HT_MCS_RATE{ HT_MCS7 = 0x00000080, HT_MCS8 = 0x00000100, HT_MCS9 = 0x00000200, - HT_MCS10 = 0x00000400, - HT_MCS11 = 0x00000800, - HT_MCS12 = 0x00001000, - HT_MCS13 = 0x00002000, - HT_MCS14 = 0x00004000, - HT_MCS15 = 0x00008000, - // Do not define MCS32 here although 8190 support MCS32 -}HT_MCS_RATE,*PHT_MCS_RATE; - -// -// Represent Channel Width in HT Capabilities -// -typedef enum _HT_CHANNEL_WIDTH{ - HT_CHANNEL_WIDTH_20 = 0, + HT_MCS10 = 0x00000400, + HT_MCS11 = 0x00000800, + HT_MCS12 = 0x00001000, + HT_MCS13 = 0x00002000, + HT_MCS14 = 0x00004000, + HT_MCS15 = 0x00008000, + /* Do not define MCS32 here although 8190 support MCS32 */ +} HT_MCS_RATE, *PHT_MCS_RATE; + +/* Represent Channel Width in HT Capabilities */ +typedef enum _HT_CHANNEL_WIDTH { + HT_CHANNEL_WIDTH_20 = 0, HT_CHANNEL_WIDTH_20_40 = 1, -}HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; +} HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; -// -// Represent Extension Channel Offset in HT Capabilities -// This is available only in 40Mhz mode. -// -typedef enum _HT_EXTCHNL_OFFSET{ +/* Represent Extension Channel Offset in HT Capabilities + * This is available only in 40Mhz mode. */ +typedef enum _HT_EXTCHNL_OFFSET { HT_EXTCHNL_OFFSET_NO_EXT = 0, - HT_EXTCHNL_OFFSET_UPPER = 1, + HT_EXTCHNL_OFFSET_UPPER = 1, HT_EXTCHNL_OFFSET_NO_DEF = 2, - HT_EXTCHNL_OFFSET_LOWER = 3, -}HT_EXTCHNL_OFFSET, *PHT_EXTCHNL_OFFSET; - -typedef enum _CHNLOP{ - CHNLOP_NONE = 0, // No Action now - CHNLOP_SCAN = 1, // Scan in progress - CHNLOP_SWBW = 2, // Bandwidth switching in progress - CHNLOP_SWCHNL = 3, // Software Channel switching in progress + HT_EXTCHNL_OFFSET_LOWER = 3, +} HT_EXTCHNL_OFFSET, *PHT_EXTCHNL_OFFSET; + +typedef enum _CHNLOP { + CHNLOP_NONE = 0, /* No Action now */ + CHNLOP_SCAN = 1, /* Scan in progress */ + CHNLOP_SWBW = 2, /* Bandwidth switching in progress */ + CHNLOP_SWCHNL = 3, /* Software Channel switching in progress */ } CHNLOP, *PCHNLOP; -// Determine if the Channel Operation is in progress +/* Determine if the Channel Operation is in progress */ #define CHHLOP_IN_PROGRESS(_pHTInfo) \ - ((_pHTInfo)->ChnlOp > CHNLOP_NONE) ? TRUE : FALSE + (((_pHTInfo)->ChnlOp > CHNLOP_NONE) ? TRUE : FALSE) -typedef enum _HT_ACTION{ +typedef enum _HT_ACTION { ACT_RECOMMAND_WIDTH = 0, ACT_MIMO_PWR_SAVE = 1, - ACT_PSMP = 2, + ACT_PSMP = 2, ACT_SET_PCO_PHASE = 3, - ACT_MIMO_CHL_MEASURE = 4, - ACT_RECIPROCITY_CORRECT = 5, + ACT_MIMO_CHL_MEASURE = 4, + ACT_RECIPROCITY_CORRECT = 5, ACT_MIMO_CSI_MATRICS = 6, - ACT_MIMO_NOCOMPR_STEER = 7, + ACT_MIMO_NOCOMPR_STEER = 7, ACT_MIMO_COMPR_STEER = 8, ACT_ANTENNA_SELECT = 9, } HT_ACTION, *PHT_ACTION; -/* 2007/06/07 MH Define sub-carrier mode for 40MHZ. */ -typedef enum _HT_Bandwidth_40MHZ_Sub_Carrier{ +/* Define sub-carrier mode for 40MHZ. */ +typedef enum _HT_Bandwidth_40MHZ_Sub_Carrier { SC_MODE_DUPLICATE = 0, - SC_MODE_LOWER = 1, - SC_MODE_UPPER = 2, + SC_MODE_LOWER = 1, + SC_MODE_UPPER = 2, SC_MODE_FULL40MHZ = 3, -}HT_BW40_SC_E; +} HT_BW40_SC_E; -typedef struct _HT_CAPABILITY_ELE{ +typedef struct _HT_CAPABILITY_ELE { - //HT capability info + /* HT capability info */ u8 AdvCoding:1; u8 ChlWidth:1; u8 MimoPwrSave:2; @@ -127,32 +118,32 @@ typedef struct _HT_CAPABILITY_ELE{ u8 Rsvd1:1; u8 LSigTxopProtect:1; - //MAC HT parameters info + /* MAC HT parameters info */ u8 MaxRxAMPDUFactor:2; u8 MPDUDensity:3; u8 Rsvd2:3; - //Supported MCS set + /* Supported MCS set */ u8 MCS[16]; - //Extended HT Capability Info + /* Extended HT Capability Info */ u16 ExtHTCapInfo; - //TXBF Capabilities + /* TXBF Capabilities */ u8 TxBFCap[4]; - //Antenna Selection Capabilities + /* Antenna Selection Capabilities */ u8 ASCap; -}__attribute__((packed)) HT_CAPABILITY_ELE, *PHT_CAPABILITY_ELE; +} __packed HT_CAPABILITY_ELE, *PHT_CAPABILITY_ELE; -//------------------------------------------------------------ -// The HT Information element is present in beacons -// Only AP is required to include this element -//------------------------------------------------------------ +/*------------------------------------------------------------ + * The HT Information element is present in beacons + * Only AP is required to include this element + *------------------------------------------------------------*/ -typedef struct _HT_INFORMATION_ELE{ +typedef struct _HT_INFORMATION_ELE { u8 ControlChl; u8 ExtChlOffset:2; @@ -177,146 +168,146 @@ typedef struct _HT_INFORMATION_ELE{ u8 Rsvd4:4; u8 BasicMSC[16]; -}__attribute__((packed)) HT_INFORMATION_ELE, *PHT_INFORMATION_ELE; +} __packed HT_INFORMATION_ELE, *PHT_INFORMATION_ELE; -// -// MIMO Power Save control field. -// This is appear in MIMO Power Save Action Frame -// -typedef struct _MIMOPS_CTRL{ +/* MIMO Power Save control field. + * This is appear in MIMO Power Save Action Frame */ +typedef struct _MIMOPS_CTRL { u8 MimoPsEnable:1; u8 MimoPsMode:1; u8 Reserved:6; } MIMOPS_CTRL, *PMIMOPS_CTRL; -typedef enum _HT_SPEC_VER{ +typedef enum _HT_SPEC_VER { HT_SPEC_VER_IEEE = 0, HT_SPEC_VER_EWC = 1, -}HT_SPEC_VER, *PHT_SPEC_VER; +} HT_SPEC_VER, *PHT_SPEC_VER; -typedef enum _HT_AGGRE_MODE_E{ +typedef enum _HT_AGGRE_MODE_E { HT_AGG_AUTO = 0, HT_AGG_FORCE_ENABLE = 1, HT_AGG_FORCE_DISABLE = 2, -}HT_AGGRE_MODE_E, *PHT_AGGRE_MODE_E; - -//------------------------------------------------------------ -// The Data structure is used to keep HT related variables when card is -// configured as non-AP STA mode. **Note** Current_xxx should be set -// to default value in HTInitializeHTInfo() -//------------------------------------------------------------ - -typedef struct _RT_HIGH_THROUGHPUT{ -// DECLARE_RT_OBJECT(_RT_HIGH_THROUGHPUT); - u8 bEnableHT; - u8 bCurrentHTSupport; - - u8 bRegBW40MHz; // Tx 40MHz channel capability - u8 bCurBW40MHz; // Tx 40MHz channel capability - - u8 bRegShortGI40MHz; // Tx Short GI for 40Mhz - u8 bCurShortGI40MHz; // Tx Short GI for 40MHz - - u8 bRegShortGI20MHz; // Tx Short GI for 20MHz - u8 bCurShortGI20MHz; // Tx Short GI for 20MHz - - u8 bRegSuppCCK; // Tx CCK rate capability - u8 bCurSuppCCK; // Tx CCK rate capability - - // 802.11n spec version for "peer" - HT_SPEC_VER ePeerHTSpecVer; - +} HT_AGGRE_MODE_E, *PHT_AGGRE_MODE_E; - // HT related information for "Self" - HT_CAPABILITY_ELE SelfHTCap; // This is HT cap element sent to peer STA, which also indicate HT Rx capabilities. - HT_INFORMATION_ELE SelfHTInfo; // This is HT info element sent to peer STA, which also indicate HT Rx capabilities. +/*---------------------------------------------------------------------------- + * The Data structure is used to keep HT related variables when card is + * configured as non-AP STA mode. + * **Note** Current_xxx should be set to default value in HTInitializeHTInfo() + *----------------------------------------------------------------------------*/ - // HT related information for "Peer" - u8 PeerHTCapBuf[32]; - u8 PeerHTInfoBuf[32]; - - - // A-MSDU related - u8 bAMSDU_Support; // This indicates Tx A-MSDU capability - u16 nAMSDU_MaxSize; // This indicates Tx A-MSDU capability - u8 bCurrent_AMSDU_Support; // This indicates Tx A-MSDU capability - u16 nCurrent_AMSDU_MaxSize; // This indicates Tx A-MSDU capability - - - // AMPDU related <2006.08.10 Emily> - u8 bAMPDUEnable; // This indicate Tx A-MPDU capability - u8 bCurrentAMPDUEnable; // This indicate Tx A-MPDU capability - u8 AMPDU_Factor; // This indicate Tx A-MPDU capability - u8 CurrentAMPDUFactor; // This indicate Tx A-MPDU capability - u8 MPDU_Density; // This indicate Tx A-MPDU capability - u8 CurrentMPDUDensity; // This indicate Tx A-MPDU capability +typedef struct _RT_HIGH_THROUGHPUT { + u8 bEnableHT; + u8 bCurrentHTSupport; + /* Tx 40MHz channel capability */ + u8 bRegBW40MHz; + u8 bCurBW40MHz; + /* Tx Short GI for 40Mhz */ + u8 bRegShortGI40MHz; + u8 bCurShortGI40MHz; + /* Tx Short GI for 20MHz */ + u8 bRegShortGI20MHz; + u8 bCurShortGI20MHz; + /* Tx CCK rate capability */ + u8 bRegSuppCCK; + u8 bCurSuppCCK; + + /* 802.11n spec version for "peer" */ + HT_SPEC_VER ePeerHTSpecVer; + + + /* HT related information for "Self" */ + /* This is HT cap element sent to peer STA, which also indicate + * HT Rx capabilities. */ + HT_CAPABILITY_ELE SelfHTCap; + HT_INFORMATION_ELE SelfHTInfo; + + /* HT related information for "Peer" */ + u8 PeerHTCapBuf[32]; + u8 PeerHTInfoBuf[32]; + + + /* A-MSDU related */ + /* This indicates Tx A-MSDU capability */ + u8 bAMSDU_Support; + u16 nAMSDU_MaxSize; + u8 bCurrent_AMSDU_Support; + u16 nCurrent_AMSDU_MaxSize; + + + /* A-MPDU related */ + /* This indicate Tx A-MPDU capability */ + u8 bAMPDUEnable; + u8 bCurrentAMPDUEnable; + u8 AMPDU_Factor; + u8 CurrentAMPDUFactor; + u8 MPDU_Density; + u8 CurrentMPDUDensity; - // Forced A-MPDU enable - HT_AGGRE_MODE_E ForcedAMPDUMode; - u8 ForcedAMPDUFactor; - u8 ForcedMPDUDensity; + /* Forced A-MPDU enable */ + HT_AGGRE_MODE_E ForcedAMPDUMode; + u8 ForcedAMPDUFactor; + u8 ForcedMPDUDensity; - // Forced A-MSDU enable - HT_AGGRE_MODE_E ForcedAMSDUMode; - u16 ForcedAMSDUMaxSize; + /* Forced A-MSDU enable */ + HT_AGGRE_MODE_E ForcedAMSDUMode; + u16 ForcedAMSDUMaxSize; - u8 bForcedShortGI; + u8 bForcedShortGI; - u8 CurrentOpMode; + u8 CurrentOpMode; - // MIMO PS related - u8 SelfMimoPs; - u8 PeerMimoPs; + /* MIMO PS related */ + u8 SelfMimoPs; + u8 PeerMimoPs; - // 40MHz Channel Offset settings. + /* 40MHz Channel Offset settings. */ HT_EXTCHNL_OFFSET CurSTAExtChnlOffset; - u8 bCurTxBW40MHz; // If we use 40 MHz to Tx - u8 PeerBandwidth; - - // For Bandwidth Switching - u8 bSwBwInProgress; - CHNLOP ChnlOp; // software switching channel in progress. By Bruce, 2008-02-15. - u8 SwBwStep; - //RT_TIMER SwBwTimer; - struct timer_list SwBwTimer; - - // For Realtek proprietary A-MPDU factor for aggregation - u8 bRegRT2RTAggregation; - u8 bCurrentRT2RTAggregation; - u8 bCurrentRT2RTLongSlotTime; - u8 szRT2RTAggBuffer[10]; - - // Rx Reorder control - u8 bRegRxReorderEnable; - u8 bCurRxReorderEnable; - u8 RxReorderWinSize; - u8 RxReorderPendingTime; - u16 RxReorderDropCounter; + u8 bCurTxBW40MHz; /* If we use 40 MHz to Tx */ + u8 PeerBandwidth; + + /* For Bandwidth Switching */ + u8 bSwBwInProgress; + CHNLOP ChnlOp; /* sw switching channel in progress. */ + u8 SwBwStep; + struct timer_list SwBwTimer; + + /* For Realtek proprietary A-MPDU factor for aggregation */ + u8 bRegRT2RTAggregation; + u8 bCurrentRT2RTAggregation; + u8 bCurrentRT2RTLongSlotTime; + u8 szRT2RTAggBuffer[10]; + + /* Rx Reorder control */ + u8 bRegRxReorderEnable; + u8 bCurRxReorderEnable; + u8 RxReorderWinSize; + u8 RxReorderPendingTime; + u16 RxReorderDropCounter; #ifdef USB_TX_DRIVER_AGGREGATION_ENABLE - u8 UsbTxAggrNum; + u8 UsbTxAggrNum; #endif #ifdef USB_RX_AGGREGATION_SUPPORT - u8 UsbRxFwAggrEn; - u8 UsbRxFwAggrPageNum; - u8 UsbRxFwAggrPacketNum; - u8 UsbRxFwAggrTimeout; + u8 UsbRxFwAggrEn; + u8 UsbRxFwAggrPageNum; + u8 UsbRxFwAggrPacketNum; + u8 UsbRxFwAggrTimeout; #endif - // Add for Broadcom(Linksys) IOT. Joseph - u8 bIsPeerBcm; + /* Add for Broadcom(Linksys) IOT. */ + u8 bIsPeerBcm; - // For IOT issue. - u32 IOTAction; -}RT_HIGH_THROUGHPUT, *PRT_HIGH_THROUGHPUT; + /* For IOT issue. */ + u32 IOTAction; +} RT_HIGH_THROUGHPUT, *PRT_HIGH_THROUGHPUT; -//------------------------------------------------------------ -// The Data structure is used to keep HT related variable for "each Sta" -// when card is configured as "AP mode" -//------------------------------------------------------------ +/*---------------------------------------------------------------------- + * The Data structure is used to keep HT related variable for "each Sta" + * when card is configured as "AP mode" + *----------------------------------------------------------------------*/ -typedef struct _RT_HTINFO_STA_ENTRY{ +typedef struct _RT_HTINFO_STA_ENTRY { u8 bEnableHT; u8 bSupportCck; @@ -335,56 +326,54 @@ typedef struct _RT_HTINFO_STA_ENTRY{ u8 McsRateSet[16]; -}RT_HTINFO_STA_ENTRY, *PRT_HTINFO_STA_ENTRY; +} RT_HTINFO_STA_ENTRY, *PRT_HTINFO_STA_ENTRY; -//------------------------------------------------------------ -// The Data structure is used to keep HT related variable for "each AP" -// when card is configured as "STA mode" -//------------------------------------------------------------ +/*--------------------------------------------------------------------- + * The Data structure is used to keep HT related variable for "each AP" + * when card is configured as "STA mode" + *---------------------------------------------------------------------*/ -typedef struct _BSS_HT{ +typedef struct _BSS_HT { u8 bdSupportHT; - // HT related elements - u8 bdHTCapBuf[32]; - u16 bdHTCapLen; - u8 bdHTInfoBuf[32]; - u16 bdHTInfoLen; + /* HT related elements */ + u8 bdHTCapBuf[32]; + u16 bdHTCapLen; + u8 bdHTInfoBuf[32]; + u16 bdHTInfoLen; - HT_SPEC_VER bdHTSpecVer; - //HT_CAPABILITY_ELE bdHTCapEle; - //HT_INFORMATION_ELE bdHTInfoEle; + HT_SPEC_VER bdHTSpecVer; - u8 bdRT2RTAggregation; - u8 bdRT2RTLongSlotTime; -}BSS_HT, *PBSS_HT; + u8 bdRT2RTAggregation; + u8 bdRT2RTLongSlotTime; +} BSS_HT, *PBSS_HT; -typedef struct _MIMO_RSSI{ +typedef struct _MIMO_RSSI { u32 EnableAntenna; u32 AntennaA; u32 AntennaB; u32 AntennaC; u32 AntennaD; u32 Average; -}MIMO_RSSI, *PMIMO_RSSI; +} MIMO_RSSI, *PMIMO_RSSI; -typedef struct _MIMO_EVM{ +typedef struct _MIMO_EVM { u32 EVM1; - u32 EVM2; -}MIMO_EVM, *PMIMO_EVM; + u32 EVM2; +} MIMO_EVM, *PMIMO_EVM; -typedef struct _FALSE_ALARM_STATISTICS{ +typedef struct _FALSE_ALARM_STATISTICS { u32 Cnt_Parity_Fail; - u32 Cnt_Rate_Illegal; + u32 Cnt_Rate_Illegal; u32 Cnt_Crc8_fail; u32 Cnt_all; -}FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS; +} FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS; -#endif //__INC_HTTYPE_H +#endif diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c index 56144014b7c9..7bdcbd39a3b2 100644 --- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c +++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c @@ -62,105 +62,6 @@ rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen) } /*----------------------------------------------------------------------------- - * Function: cmpk_message_handle_tx() - * - * Overview: Driver internal module can call the API to send message to - * firmware side. For example, you can send a debug command packet. - * Or you can send a request for FW to modify RLX4181 LBUS HW bank. - * Otherwise, you can change MAC/PHT/RF register by firmware at - * run time. We do not support message more than one segment now. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 05/06/2008 amy porting from windows code. - * - *---------------------------------------------------------------------------*/ -extern rt_status cmpk_message_handle_tx(struct net_device *dev, - u8 *codevirtualaddress, - u32 packettype, u32 buffer_len) -{ - - bool rt_status = true; -#ifdef RTL8192U - return rt_status; -#else - struct r8192_priv *priv = ieee80211_priv(dev); - u16 frag_threshold; - u16 frag_length, frag_offset = 0; - - rt_firmware *pfirmware = priv->pFirmware; - struct sk_buff *skb; - unsigned char *seg_ptr; - cb_desc *tcb_desc; - u8 bLastIniPkt; - - firmware_init_param(dev); - /* Fragmentation might be required */ - frag_threshold = pfirmware->cmdpacket_frag_thresold; - do { - if ((buffer_len - frag_offset) > frag_threshold) { - frag_length = frag_threshold; - bLastIniPkt = 0; - - } else { - frag_length = buffer_len - frag_offset; - bLastIniPkt = 1; - - } - - /* Allocate skb buffer to contain firmware info and tx - descriptor info add 4 to avoid packet appending overflow. */ -#ifdef RTL8192U - skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); -#else - skb = dev_alloc_skb(frag_length + 4); -#endif - memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); - tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); - tcb_desc->queue_index = TXCMD_QUEUE; - tcb_desc->bCmdOrInit = packettype; - tcb_desc->bLastIniPkt = bLastIniPkt; - -#ifdef RTL8192U - skb_reserve(skb, USB_HWDESC_HEADER_LEN); -#endif - - seg_ptr = skb_put(skb, buffer_len); - /* - * Transform from little endian to big endian - * and pending zero - */ - memcpy(seg_ptr, codevirtualaddress, buffer_len); - tcb_desc->txbuf_size = (u16)buffer_len; - - - if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) || - (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) || - (priv->ieee80211->queue_stop)) { - RT_TRACE(COMP_FIRMWARE, "======> tx full!\n"); - skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); - } else { - priv->ieee80211->softmac_hard_start_xmit(skb, dev); - } - - codevirtualaddress += frag_length; - frag_offset += frag_length; - - } while (frag_offset < buffer_len); - - return rt_status; - - -#endif -} - -/*----------------------------------------------------------------------------- * Function: cmpk_counttxstatistic() * * Overview: @@ -593,8 +494,8 @@ static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg) * 05/06/2008 amy Create Version 0 porting from windows code. * *---------------------------------------------------------------------------*/ -extern u32 cmpk_message_handle_rx(struct net_device *dev, - struct ieee80211_rx_stats *pstats) +u32 cmpk_message_handle_rx(struct net_device *dev, + struct ieee80211_rx_stats *pstats) { int total_length; u8 cmd_length, exe_cnt = 0; diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.h b/drivers/staging/rtl8192u/r819xU_cmdpkt.h index ebe403270a5b..52cd437ef7bb 100644 --- a/drivers/staging/rtl8192u/r819xU_cmdpkt.h +++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.h @@ -1,17 +1,17 @@ #ifndef R819XUSB_CMDPKT_H #define R819XUSB_CMDPKT_H /* Different command packet have dedicated message length and definition. */ -#define CMPK_RX_TX_FB_SIZE sizeof(cmpk_txfb_t) //20 -#define CMPK_TX_SET_CONFIG_SIZE sizeof(cmpk_set_cfg_t) //16 -#define CMPK_BOTH_QUERY_CONFIG_SIZE sizeof(cmpk_set_cfg_t) //16 -#define CMPK_RX_TX_STS_SIZE sizeof(cmpk_tx_status_t)// -#define CMPK_RX_DBG_MSG_SIZE sizeof(cmpk_rx_dbginfo_t)// -#define CMPK_TX_RAHIS_SIZE sizeof(cmpk_tx_rahis_t) +#define CMPK_RX_TX_FB_SIZE sizeof(cmpk_txfb_t) /* 20 */ +#define CMPK_TX_SET_CONFIG_SIZE sizeof(cmpk_set_cfg_t) /* 16 */ +#define CMPK_BOTH_QUERY_CONFIG_SIZE sizeof(cmpk_set_cfg_t) /* 16 */ +#define CMPK_RX_TX_STS_SIZE sizeof(cmpk_tx_status_t) +#define CMPK_RX_DBG_MSG_SIZE sizeof(cmpk_rx_dbginfo_t) +#define CMPK_TX_RAHIS_SIZE sizeof(cmpk_tx_rahis_t) /* 2008/05/08 amy For USB constant. */ -#define ISR_TxBcnOk BIT27 // Transmit Beacon OK -#define ISR_TxBcnErr BIT26 // Transmit Beacon Error -#define ISR_BcnTimerIntr BIT13 // Beacon Timer Interrupt +#define ISR_TxBcnOk BIT27 /* Transmit Beacon OK */ +#define ISR_TxBcnErr BIT26 /* Transmit Beacon Error */ +#define ISR_BcnTimerIntr BIT13 /* Beacon Timer Interrupt */ /* Define element ID of command packet. */ @@ -20,182 +20,172 @@ /* Define different command packet structure. */ /* 1. RX side: TX feedback packet. */ typedef struct tag_cmd_pkt_tx_feedback { - // DWORD 0 + /* DWORD 0 */ u8 element_id; /* Command packet type. */ u8 length; /* Command packet length. */ - /* 2007/07/05 MH Change tx feedback info field. */ + /* Change tx feedback info field. */ /*------TX Feedback Info Field */ - u8 TID:4; /* */ - u8 fail_reason:3; /* */ + u8 TID:4; + u8 fail_reason:3; u8 tok:1; /* Transmit ok. */ - u8 reserve1:4; /* */ - u8 pkt_type:2; /* */ - u8 bandwidth:1; /* */ - u8 qos_pkt:1; /* */ + u8 reserve1:4; + u8 pkt_type:2; + u8 bandwidth:1; + u8 qos_pkt:1; - // DWORD 1 - u8 reserve2; /* */ + /* DWORD 1 */ + u8 reserve2; /*------TX Feedback Info Field */ - u8 retry_cnt; /* */ - u16 pkt_id; /* */ + u8 retry_cnt; + u16 pkt_id; - // DWORD 3 - u16 seq_num; /* */ + /* DWORD 3 */ + u16 seq_num; u8 s_rate; /* Start rate. */ u8 f_rate; /* Final rate. */ - // DWORD 4 - u8 s_rts_rate; /* */ - u8 f_rts_rate; /* */ - u16 pkt_length; /* */ + /* DWORD 4 */ + u8 s_rts_rate; + u8 f_rts_rate; + u16 pkt_length; - // DWORD 5 - u16 reserve3; /* */ - u16 duration; /* */ -}cmpk_txfb_t; + /* DWORD 5 */ + u16 reserve3; + u16 duration; +} cmpk_txfb_t; /* 2. RX side: Interrupt status packet. It includes Beacon State, - Beacon Timer Interrupt and other useful informations in MAC ISR Reg. */ + * Beacon Timer Interrupt and other useful informations in MAC ISR Reg. */ typedef struct tag_cmd_pkt_interrupt_status { u8 element_id; /* Command packet type. */ u8 length; /* Command packet length. */ u16 reserve; - u32 interrupt_status; /* Interrupt Status. */ -}cmpk_intr_sta_t; + u32 interrupt_status; /* Interrupt Status. */ +} cmpk_intr_sta_t; /* 3. TX side: Set configuration packet. */ typedef struct tag_cmd_pkt_set_configuration { u8 element_id; /* Command packet type. */ u8 length; /* Command packet length. */ - u16 reserve1; /* */ + u16 reserve1; + /* Configuration info. */ u8 cfg_reserve1:3; - u8 cfg_size:2; /* Configuration info. */ - u8 cfg_type:2; /* Configuration info. */ - u8 cfg_action:1; /* Configuration info. */ - u8 cfg_reserve2; /* Configuration info. */ - u8 cfg_page:4; /* Configuration info. */ - u8 cfg_reserve3:4; /* Configuration info. */ - u8 cfg_offset; /* Configuration info. */ - u32 value; /* */ - u32 mask; /* */ -}cmpk_set_cfg_t; + u8 cfg_size:2; + u8 cfg_type:2; + u8 cfg_action:1; + u8 cfg_reserve2; + u8 cfg_page:4; + u8 cfg_reserve3:4; + u8 cfg_offset; + u32 value; + u32 mask; +} cmpk_set_cfg_t; /* 4. Both side : TX/RX query configuraton packet. The query structure is the same as set configuration. */ #define cmpk_query_cfg_t cmpk_set_cfg_t /* 5. Multi packet feedback status. */ -typedef struct tag_tx_stats_feedback { // PJ quick rxcmd 09042007 - // For endian transfer --> Driver will not the same as firmware structure. - // DW 0 +typedef struct tag_tx_stats_feedback { + /* For endian transfer --> Driver will not the same as + firmware structure. */ + /* DW 0 */ u16 reserve1; - u8 length; // Command packet length - u8 element_id; // Command packet type + u8 length; /* Command packet length */ + u8 element_id; /* Command packet type */ - // DW 1 - u16 txfail; // Tx Fail count - u16 txok; // Tx ok count + /* DW 1 */ + u16 txfail; /* Tx fail count */ + u16 txok; /* Tx ok count */ - // DW 2 - u16 txmcok; // tx multicast - u16 txretry; // Tx Retry count + /* DW 2 */ + u16 txmcok; /* Tx multicast */ + u16 txretry; /* Tx retry count */ - // DW 3 - u16 txucok; // tx unicast - u16 txbcok; // tx broadcast + /* DW 3 */ + u16 txucok; /* Tx unicast */ + u16 txbcok; /* Tx broadcast */ - // DW 4 - u16 txbcfail; // - u16 txmcfail; // + /* DW 4 */ + u16 txbcfail; + u16 txmcfail; - // DW 5 - u16 reserve2; // - u16 txucfail; // + /* DW 5 */ + u16 reserve2; + u16 txucfail; - // DW 6-8 + /* DW 6-8 */ u32 txmclength; u32 txbclength; u32 txuclength; - // DW 9 + /* DW 9 */ u16 reserve3_23; u8 reserve3_1; u8 rate; -}__attribute__((packed)) cmpk_tx_status_t; +} __packed cmpk_tx_status_t; /* 6. Debug feedback message. */ -/* 2007/10/23 MH Define RX debug message */ +/* Define RX debug message */ typedef struct tag_rx_debug_message_feedback { - // For endian transfer --> for driver - // DW 0 + /* For endian transfer --> for driver */ + /* DW 0 */ u16 reserve1; - u8 length; // Command packet length - u8 element_id; // Command packet type + u8 length; /* Command packet length */ + u8 element_id; /* Command packet type */ - // DW 1-?? - // Variable debug message. + /* DW 1-?? */ + /* Variable debug message. */ -}cmpk_rx_dbginfo_t; +} cmpk_rx_dbginfo_t; -/* 2008/03/20 MH Define transmit rate history. For big endian format. */ +/* Define transmit rate history. For big endian format. */ typedef struct tag_tx_rate_history { - // For endian transfer --> for driver - // DW 0 - u8 element_id; // Command packet type - u8 length; // Command packet length + /* For endian transfer --> for driver */ + /* DW 0 */ + u8 element_id; /* Command packet type */ + u8 length; /* Command packet length */ u16 reserved1; - // DW 1-2 CCK rate counter + /* DW 1-2 CCK rate counter */ u16 cck[4]; - // DW 3-6 + /* DW 3-6 */ u16 ofdm[8]; - // DW 7-14 - //UINT16 MCS_BW0_SG0[16]; - - // DW 15-22 - //UINT16 MCS_BW1_SG0[16]; - - // DW 23-30 - //UINT16 MCS_BW0_SG1[16]; - - // DW 31-38 - //UINT16 MCS_BW1_SG1[16]; - - // DW 7-14 BW=0 SG=0 - // DW 15-22 BW=1 SG=0 - // DW 23-30 BW=0 SG=1 - // DW 31-38 BW=1 SG=1 + /* DW 7-14 BW=0 SG=0 + * DW 15-22 BW=1 SG=0 + * DW 23-30 BW=0 SG=1 + * DW 31-38 BW=1 SG=1 + */ u16 ht_mcs[4][16]; -}__attribute__((packed)) cmpk_tx_rahis_t; - -typedef enum tag_command_packet_directories -{ - RX_TX_FEEDBACK = 0, - RX_INTERRUPT_STATUS = 1, - TX_SET_CONFIG = 2, - BOTH_QUERY_CONFIG = 3, - RX_TX_STATUS = 4, - RX_DBGINFO_FEEDBACK = 5, - RX_TX_PER_PKT_FEEDBACK = 6, - RX_TX_RATE_HISTORY = 7, - RX_CMD_ELE_MAX -}cmpk_element_e; - -typedef enum _rt_status{ +} __packed cmpk_tx_rahis_t; + +typedef enum tag_command_packet_directories { + RX_TX_FEEDBACK = 0, + RX_INTERRUPT_STATUS = 1, + TX_SET_CONFIG = 2, + BOTH_QUERY_CONFIG = 3, + RX_TX_STATUS = 4, + RX_DBGINFO_FEEDBACK = 5, + RX_TX_PER_PKT_FEEDBACK = 6, + RX_TX_RATE_HISTORY = 7, + RX_CMD_ELE_MAX +} cmpk_element_e; + +typedef enum _rt_status { RT_STATUS_SUCCESS, RT_STATUS_FAILURE, RT_STATUS_PENDING, RT_STATUS_RESOURCE -}rt_status,*prt_status; - -extern rt_status cmpk_message_handle_tx(struct net_device *dev, u8 *codevirtualaddress, u32 packettype, u32 buffer_len); +} rt_status, *prt_status; -extern u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats); -extern rt_status SendTxCommandPacket( struct net_device *dev, void *pData, u32 DataLen); +extern u32 cmpk_message_handle_rx(struct net_device *dev, + struct ieee80211_rx_stats *pstats); +extern rt_status SendTxCommandPacket(struct net_device *dev, + void *pData, u32 DataLen); #endif diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c index bb924ac97e47..d6a6de3a64f5 100644 --- a/drivers/staging/rtl8192u/r819xU_firmware.c +++ b/drivers/staging/rtl8192u/r819xU_firmware.c @@ -61,20 +61,16 @@ bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, u32 buff /* Allocate skb buffer to contain firmware info and tx descriptor info * add 4 to avoid packet appending overflow. * */ - #ifdef RTL8192U skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); - #else - skb = dev_alloc_skb(frag_length + 4); - #endif + if (!skb) + return false; memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); tcb_desc->queue_index = TXCMD_QUEUE; tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; tcb_desc->bLastIniPkt = bLastIniPkt; - #ifdef RTL8192U skb_reserve(skb, USB_HWDESC_HEADER_LEN); - #endif seg_ptr = skb->data; /* * Transform from little endian to big endian @@ -299,16 +295,10 @@ bool init_firmware(struct net_device *dev) mapped_file = pfirmware->firmware_buf; file_length = fw_entry->size; } else { -#ifdef RTL8190P - memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size); - mapped_file = pfirmware->firmware_buf; - file_length = fw_entry->size; -#else memset(pfirmware->firmware_buf,0,128); memcpy(&pfirmware->firmware_buf[128],fw_entry->data,fw_entry->size); mapped_file = pfirmware->firmware_buf; file_length = fw_entry->size + 128; -#endif } pfirmware->firmware_buf_size = file_length; }else if (rst_opt == OPT_FIRMWARE_RESET ) { @@ -340,15 +330,6 @@ bool init_firmware(struct net_device *dev) * will set polling bit when firmware code is also configured */ pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; -#ifdef RTL8190P - // To initialize IMEM, CPU move code from 0x80000080, hence, we send 0x80 byte packet - rt_status = fwSendNullPacket(dev, RTL8190_CPU_START_OFFSET); - if (rt_status != true) - { - RT_TRACE(COMP_INIT, "fwSendNullPacket() fail ! \n"); - goto download_firmware_fail; - } -#endif //mdelay(1000); /* * To initialize IMEM, CPU move code from 0x80000080, diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c index a6fac081e42c..39cd426bc5e5 100644 --- a/drivers/staging/rtl8192u/r819xU_phy.c +++ b/drivers/staging/rtl8192u/r819xU_phy.c @@ -1713,7 +1713,7 @@ void InitialGain819xUsb(struct net_device *dev, u8 Operation) queue_delayed_work(priv->priv_wq, &priv->initialgain_operate_wq, 0); } -extern void InitialGainOperateWorkItemCallBack(struct work_struct *work) +void InitialGainOperateWorkItemCallBack(struct work_struct *work) { struct delayed_work *dwork = container_of(work, struct delayed_work, work); @@ -1799,12 +1799,6 @@ extern void InitialGainOperateWorkItemCallBack(struct work_struct *work) RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xa0a is %x\n", priv->initgain_backup.cca); -#ifdef RTL8190P - SetTxPowerLevel8190(Adapter, priv->CurrentChannel); -#endif -#ifdef RTL8192E - SetTxPowerLevel8190(Adapter, priv->CurrentChannel); -#endif rtl8192_phy_setTxPower(dev, priv->ieee80211->current_network.channel); if (dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) diff --git a/drivers/staging/rtl8192u/r819xU_phy.h b/drivers/staging/rtl8192u/r819xU_phy.h index f3c352a10fe0..66cbe3f9cafd 100644 --- a/drivers/staging/rtl8192u/r819xU_phy.h +++ b/drivers/staging/rtl8192u/r819xU_phy.h @@ -23,7 +23,7 @@ typedef struct _SwChnlCmd { u32 Para1; u32 Para2; u32 msDelay; -} __attribute__ ((packed)) SwChnlCmd; +} __packed SwChnlCmd; extern u32 rtl819XMACPHY_Array_PG[]; extern u32 rtl819XPHY_REG_1T2RArray[]; diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c index 6e81ba0eaf1e..82a77b45fb50 100644 --- a/drivers/staging/rtl8712/os_intfs.c +++ b/drivers/staging/rtl8712/os_intfs.c @@ -141,7 +141,7 @@ static uint loadparam(struct _adapter *padapter, struct net_device *pnetdev) registry_par->ssid.SsidLength = 3; registry_par->channel = (u8)channel; registry_par->wireless_mode = (u8)wireless_mode; - registry_par->vrtl_carrier_sense = (u8)vrtl_carrier_sense ; + registry_par->vrtl_carrier_sense = (u8)vrtl_carrier_sense; registry_par->vcs_type = (u8)vcs_type; registry_par->frag_thresh = (u16)frag_thresh; registry_par->preamble = (u8)preamble; diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c index 088647cdca99..5b6a96e3bd7b 100644 --- a/drivers/staging/rtl8712/rtl8712_cmd.c +++ b/drivers/staging/rtl8712/rtl8712_cmd.c @@ -62,7 +62,7 @@ static void check_hw_pbc(struct _adapter *padapter) r8712_write8(padapter, GPIO_IO_SEL, tmp1byte); tmp1byte = r8712_read8(padapter, GPIO_CTRL); if (tmp1byte == 0xff) - return ; + return; if (tmp1byte&HAL_8192S_HW_GPIO_WPS_BIT) { /* Here we only set bPbcPressed to true * After trigger PBC, the variable will be set to false */ @@ -381,7 +381,7 @@ _next: *pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) | (pcmd->cmdcode << 16) | (pcmdpriv->cmd_seq << 24)); - pcmdbuf += 2 ; /* 8 bytes alignment */ + pcmdbuf += 2; /* 8 bytes alignment */ memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); while (check_cmd_fifo(padapter, wr_sz) == _FAIL) { if ((padapter->bDriverStopped == true) || @@ -471,11 +471,9 @@ void r8712_event_handle(struct _adapter *padapter, uint *peventbuf) if (pevt_priv->event_seq > 127) pevt_priv->event_seq = 0; peventbuf = peventbuf + 2; /* move to event content, 8 bytes alignment */ - if (peventbuf) { - event_callback = wlanevents[evt_code].event_callback; - if (event_callback) - event_callback(padapter, (u8 *)peventbuf); - } + event_callback = wlanevents[evt_code].event_callback; + if (event_callback) + event_callback(padapter, (u8 *)peventbuf); pevt_priv->evt_done_cnt++; _abort_event_: return; diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c index 377fca905801..c9eeb4270ab9 100644 --- a/drivers/staging/rtl8712/rtl8712_efuse.c +++ b/drivers/staging/rtl8712/rtl8712_efuse.c @@ -231,7 +231,7 @@ u16 r8712_efuse_get_current_size(struct _adapter *padapter) /* read next header */ efuse_addr = efuse_addr + (word_cnts * 2) + 1; } else - bContinual = false ; + bContinual = false; } return efuse_addr; } diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index d59a74aa3048..ea965370d1ac 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -108,7 +108,7 @@ void r8712_free_recv_priv(struct recv_priv *precvpriv) struct _adapter *padapter = precvpriv->adapter; precvbuf = (struct recv_buf *)precvpriv->precv_buf; - for (i = 0; i < NR_RECVBUFF ; i++) { + for (i = 0; i < NR_RECVBUFF; i++) { r8712_os_recvbuf_resource_free(padapter, precvbuf); precvbuf++; } @@ -268,7 +268,7 @@ union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *padapter, u8 *psta_addr; struct recv_frame_hdr *pfhdr; struct sta_info *psta; - struct sta_priv *pstapriv ; + struct sta_priv *pstapriv; struct list_head *phead; union recv_frame *prtnframe = NULL; struct __queue *pfree_recv_queue, *pdefrag_q; @@ -849,7 +849,7 @@ static void query_rx_phy_status(struct _adapter *padapter, } else { /* (1)Get RSSI for HT rate */ for (i = 0; i < ((padapter->registrypriv.rf_config) & - 0x0f) ; i++) { + 0x0f); i++) { rf_rx_num++; rx_pwr[i] = ((pphy_head[PHY_STAT_GAIN_TRSW_SHT + i] & 0x3F) * 2) - 110; diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c index f16307f5d827..7e324315e6ad 100644 --- a/drivers/staging/rtl8712/rtl871x_cmd.c +++ b/drivers/staging/rtl8712/rtl871x_cmd.c @@ -965,7 +965,7 @@ void r8712_createbss_cmd_callback(struct _adapter *padapter, psta = r8712_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress); if (psta == NULL) - goto createbss_cmd_fail ; + goto createbss_cmd_fail; } r8712_indicate_connect(padapter); } else { diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index d58aa7e3b15c..9fec6eda8731 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -820,7 +820,7 @@ static int r871x_wx_set_pmkid(struct net_device *dev, intReturn = true; blInserted = false; /* overwrite PMKID */ - for (j = 0 ; j < NUM_PMKID_CACHE; j++) { + for (j = 0; j < NUM_PMKID_CACHE; j++) { if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { /* BSSID is matched, the same AP => rewrite @@ -845,7 +845,7 @@ static int r871x_wx_set_pmkid(struct net_device *dev, PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN); psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex]. bUsed = true; - psecuritypriv->PMKIDIndex++ ; + psecuritypriv->PMKIDIndex++; if (psecuritypriv->PMKIDIndex == NUM_PMKID_CACHE) psecuritypriv->PMKIDIndex = 0; } @@ -1598,7 +1598,7 @@ static int r8711_wx_set_enc(struct net_device *dev, wep.Length = wep.KeyLength + FIELD_OFFSET(struct NDIS_802_11_WEP, KeyMaterial); } else { - wep.KeyLength = 0 ; + wep.KeyLength = 0; if (keyindex_provided == 1) { /* set key_id only, no given * KeyMaterial(erq->length==0).*/ padapter->securitypriv.PrivacyKeyIndex = key; @@ -1880,7 +1880,7 @@ static int r8711_wx_write32(struct net_device *dev, u32 data32; get_user(addr, (u32 __user *)wrqu->data.pointer); - data32 = ((u32)wrqu->data.length<<16) | (u32)wrqu->data.flags ; + data32 = ((u32)wrqu->data.length<<16) | (u32)wrqu->data.flags; r8712_write32(padapter, addr, data32); return 0; } diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c index 5d6d55e7b389..ac0baff7f090 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c @@ -153,7 +153,7 @@ uint oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv) padapter->recvpriv.rx_icv_err; *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; } else - return RNDIS_STATUS_INVALID_LENGTH ; + return RNDIS_STATUS_INVALID_LENGTH; return RNDIS_STATUS_SUCCESS; } @@ -169,7 +169,7 @@ uint oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *padapter = (struct _adapter *) (poid_par_priv->adapter_context); - u32 preamblemode = 0 ; + u32 preamblemode = 0; if (poid_par_priv->type_of_oid != QUERY_OID) return RNDIS_STATUS_NOT_ACCEPTED; @@ -522,7 +522,7 @@ uint oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv) else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ulInfo = ADHOCMODE; else - ulInfo = NOTASSOCIATED ; + ulInfo = NOTASSOCIATED; *(u32 *)poid_par_priv->information_buf = ulInfo; *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; return RNDIS_STATUS_SUCCESS; diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 659615481f6f..8fa0f9d49a8a 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -1641,7 +1641,7 @@ void r8712_update_registrypriv_dev_network(struct _adapter *adapter) struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; pdev_network->Privacy = cpu_to_le32(psecuritypriv->PrivacyAlgrthm - > 0 ? 1 : 0) ; /* adhoc no 802.1x */ + > 0 ? 1 : 0); /* adhoc no 802.1x */ pdev_network->Rssi = 0; switch (pregistrypriv->wireless_mode) { case WIRELESS_11B: @@ -1786,7 +1786,7 @@ static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) psta = r8712_get_stainfo(&padapter->stapriv, pcur_network->network.MacAddress); if (psta) { - for (i = 0; i < 16 ; i++) { + for (i = 0; i < 16; i++) { preorder_ctrl = &psta->recvreorder_ctrl[i]; preorder_ctrl->indicate_seq = 0xffff; preorder_ctrl->wend_b = 0xffff; diff --git a/drivers/staging/rtl8712/rtl871x_mp.c b/drivers/staging/rtl8712/rtl871x_mp.c index 5638d5e065ff..0563318a19ff 100644 --- a/drivers/staging/rtl8712/rtl871x_mp.c +++ b/drivers/staging/rtl8712/rtl871x_mp.c @@ -110,7 +110,7 @@ static u32 fw_iocmd_read(struct _adapter *pAdapter, struct IOCMD_STRUCT iocmd) u16 iocmd_value = iocmd.value; u8 iocmd_idx = iocmd.index; - cmd32 = (iocmd_class << 24) | (iocmd_value << 8) | iocmd_idx ; + cmd32 = (iocmd_class << 24) | (iocmd_value << 8) | iocmd_idx; if (r8712_fw_cmd(pAdapter, cmd32)) r8712_fw_cmd_data(pAdapter, &val32, 1); else @@ -128,7 +128,7 @@ static u8 fw_iocmd_write(struct _adapter *pAdapter, r8712_fw_cmd_data(pAdapter, &value, 0); msleep(100); - cmd32 = (iocmd_class << 24) | (iocmd_value << 8) | iocmd_idx ; + cmd32 = (iocmd_class << 24) | (iocmd_value << 8) | iocmd_idx; return r8712_fw_cmd(pAdapter, cmd32); } @@ -189,8 +189,8 @@ u32 r8712_rf_reg_read(struct _adapter *pAdapter, u8 path, u8 offset) u32 rf_data; struct IOCMD_STRUCT iocmd; - iocmd.cmdclass = IOCMD_CLASS_BB_RF ; - iocmd.value = rf_addr ; + iocmd.cmdclass = IOCMD_CLASS_BB_RF; + iocmd.value = rf_addr; iocmd.index = IOCMD_RF_READ_IDX; rf_data = fw_iocmd_read(pAdapter, iocmd); return rf_data; diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c index e33fd6db246d..5349669707c0 100644 --- a/drivers/staging/rtl8712/rtl871x_security.c +++ b/drivers/staging/rtl8712/rtl871x_security.c @@ -835,7 +835,7 @@ static void mix_column(u8 *in, u8 *out) u8 temp[4]; u8 tempb[4]; - for (i = 0 ; i < 4; i++) { + for (i = 0; i < 4; i++) { if ((in[i] & 0x80) == 0x80) add1b[i] = 0x1b; else @@ -1187,7 +1187,7 @@ u32 r8712_aes_encrypt(struct _adapter *padapter, u8 *pxmitframe) length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - - pattrib->icv_len ; + pattrib->icv_len; aes_cipher(prwskey, pattrib-> hdrlen, pframe, length); pframe += pxmitpriv->frag_len; @@ -1315,7 +1315,7 @@ static sint aes_decipher(u8 *key, uint hdrlen, bitwise_xor(aes_out, padded_buffer, chain_buffer); aes128k128d(key, chain_buffer, aes_out); } - for (j = 0 ; j < 8; j++) + for (j = 0; j < 8; j++) mic[j] = aes_out[j]; /* Insert MIC into payload */ for (j = 0; j < 8; j++) diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c index 1247b3d9719d..8db6849d4b24 100644 --- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c +++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c @@ -138,7 +138,7 @@ struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) } phash_list = &(pstapriv->sta_hash[index]); list_insert_tail(&psta->hash_list, phash_list); - pstapriv->asoc_sta_count++ ; + pstapriv->asoc_sta_count++; /* For the SMC router, the sequence number of first packet of WPS handshake * will be 0. In this case, this packet will be dropped by recv_decache function @@ -149,7 +149,7 @@ struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); /* for A-MPDU Rx reordering buffer control */ - for (i = 0; i < 16 ; i++) { + for (i = 0; i < 16; i++) { preorder_ctrl = &psta->recvreorder_ctrl[i]; preorder_ctrl->padapter = pstapriv->padapter; preorder_ctrl->indicate_seq = 0xffff; diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index c812d6c7dc31..dbefa43e4c2c 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -353,11 +353,6 @@ static void disable_ht_for_spec_devid(const struct usb_device_id *pdid, } } -static u8 key_2char2num(u8 hch, u8 lch) -{ - return (hex_to_bin(hch) << 4) | hex_to_bin(lch); -} - /* * drv_init() - a device potentially for us * @@ -465,16 +460,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf, r8712_efuse_pg_packet_read(padapter, offset, &pdata[i]); - if (r8712_initmac) { - /* Users specify the mac address */ - int jj, kk; - - for (jj = 0, kk = 0; jj < ETH_ALEN; - jj++, kk += 3) - mac[jj] = - key_2char2num(r8712_initmac[kk], - r8712_initmac[kk + 1]); - } else { + if (!r8712_initmac || !mac_pton(r8712_initmac, mac)) { /* Use the mac address stored in the Efuse * offset = 0x12 for usb in efuse */ diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c index 4d22bb7008f8..0ac9130faf6c 100644 --- a/drivers/staging/rtl8712/xmit_linux.c +++ b/drivers/staging/rtl8712/xmit_linux.c @@ -51,7 +51,7 @@ void _r8712_open_pktfile(_pkt *pktptr, struct pkt_file *pfile) pfile->pkt = pktptr; pfile->cur_addr = pfile->buf_start = pktptr->data; pfile->pkt_len = pfile->buf_len = pktptr->len; - pfile->cur_buffer = pfile->buf_start ; + pfile->cur_buffer = pfile->buf_start; } uint _r8712_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) diff --git a/drivers/staging/sb105x/sb_mp_register.h b/drivers/staging/sb105x/sb_mp_register.h index 304e1bcd1e3b..16de497415ee 100644 --- a/drivers/staging/sb105x/sb_mp_register.h +++ b/drivers/staging/sb105x/sb_mp_register.h @@ -15,8 +15,8 @@ #ifndef UART_SB105X_H #define UART_SB105X_H -/* - * option register +/* + * option register */ /* Device Information Register */ diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c index 6a98a208bbf2..11f5b2117457 100644 --- a/drivers/staging/sep/sep_main.c +++ b/drivers/staging/sep/sep_main.c @@ -1263,13 +1263,8 @@ static int sep_lock_user_pages(struct sep_device *sep, } /* Convert the application virtual address into a set of physical */ - down_read(¤t->mm->mmap_sem); - result = get_user_pages(current, current->mm, app_virt_addr, - num_pages, - ((in_out_flag == SEP_DRIVER_IN_FLAG) ? 0 : 1), - 0, page_array, NULL); - - up_read(¤t->mm->mmap_sem); + result = get_user_pages_fast(app_virt_addr, num_pages, + ((in_out_flag == SEP_DRIVER_IN_FLAG) ? 0 : 1), page_array); /* Check the number of pages locked - if not all then exit with error */ if (result != num_pages) { diff --git a/drivers/staging/silicom/bp_mod.h b/drivers/staging/silicom/bp_mod.h index cfa1f43fa4af..8154a7bf050f 100644 --- a/drivers/staging/silicom/bp_mod.h +++ b/drivers/staging/silicom/bp_mod.h @@ -22,7 +22,7 @@ do { \ int i; \ if (1) { \ for (i = 0; i < 1000; i++) { \ - udelay(x) ; \ + udelay(x); \ } \ } else { \ msleep(x); \ diff --git a/drivers/staging/silicom/bpctl_mod.c b/drivers/staging/silicom/bpctl_mod.c index 495272d01348..39dc92a271ab 100644 --- a/drivers/staging/silicom/bpctl_mod.c +++ b/drivers/staging/silicom/bpctl_mod.c @@ -1,11 +1,11 @@ /******************************************************************************/ /* */ -/* Bypass Control utility, Copyright (c) 2005-20011 Silicom */ +/* Bypass Control utility, Copyright (c) 2005-2011 Silicom */ /* */ /* 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, located in the file LICENSE. */ -/* Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. */ +/* Copyright(c) 2007 - 2009, 2013 Intel Corporation. All rights reserved. */ /* */ /* */ /******************************************************************************/ @@ -124,80 +124,60 @@ int bp_proc_create(void); int is_bypass_fn(struct bpctl_dev *pbpctl_dev); int get_dev_idx_bsf(int bus, int slot, int func); -static unsigned long str_to_hex(char *p); +static int bp_get_dev_idx_bsf(struct net_device *dev, int *index) +{ + struct ethtool_drvinfo drvinfo = {0}; + char *buf; + int bus, slot, func; + + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) + dev->ethtool_ops->get_drvinfo(dev, &drvinfo); + else + return -EOPNOTSUPP; + + if (!drvinfo.bus_info) + return -ENODATA; + if (!strcmp(drvinfo.bus_info, "N/A")) + return -ENODATA; + + buf = strchr(drvinfo.bus_info, ':'); + if (!buf) + return -EINVAL; + buf++; + if (sscanf(buf, "%x:%x.%x", &bus, &slot, &func) != 3) + return -EINVAL; + + *index = get_dev_idx_bsf(bus, slot, func); + return 0; +} + static int bp_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); static struct bpctl_dev *pbpctl_dev, *pbpctl_dev_m; int dev_num = 0, ret = 0, ret_d = 0, time_left = 0; + /* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */ /* return NOTIFY_DONE; */ if (!dev) return NOTIFY_DONE; - if (event == NETDEV_REGISTER) { - { - struct ethtool_drvinfo drvinfo; - char cbuf[32]; - char *buf = NULL; - char res[10]; - int i = 0, ifindex, idx_dev = 0; - int bus = 0, slot = 0, func = 0; - ifindex = dev->ifindex; - - memset(res, 0, 10); - memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); - - if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) { - memset(&drvinfo, 0, sizeof(drvinfo)); - dev->ethtool_ops->get_drvinfo(dev, &drvinfo); - } else - return NOTIFY_DONE; - if (!drvinfo.bus_info) - return NOTIFY_DONE; - if (!strcmp(drvinfo.bus_info, "N/A")) - return NOTIFY_DONE; - memcpy(&cbuf, drvinfo.bus_info, 32); - buf = &cbuf[0]; - while (*buf++ != ':') - ; - for (i = 0; i < 10; i++, buf++) { - if (*buf == ':') - break; - res[i] = *buf; - - } - buf++; - bus = str_to_hex(res); - memset(res, 0, 10); - - for (i = 0; i < 10; i++, buf++) { - if (*buf == '.') - break; - res[i] = *buf; - - } - buf++; - slot = str_to_hex(res); - func = str_to_hex(buf); - idx_dev = get_dev_idx_bsf(bus, slot, func); - - if (idx_dev != -1) { + if (event == NETDEV_REGISTER) { + int idx_dev; - bpctl_dev_arr[idx_dev].ifindex = ifindex; - bpctl_dev_arr[idx_dev].ndev = dev; + if (bp_get_dev_idx_bsf(dev, &idx_dev)) + return NOTIFY_DONE; - bypass_proc_remove_dev_sd(&bpctl_dev_arr - [idx_dev]); - bypass_proc_create_dev_sd(&bpctl_dev_arr - [idx_dev]); + if (idx_dev == -1) + return NOTIFY_DONE; - } + bpctl_dev_arr[idx_dev].ifindex = dev->ifindex; + bpctl_dev_arr[idx_dev].ndev = dev; - } + bypass_proc_remove_dev_sd(&bpctl_dev_arr[idx_dev]); + bypass_proc_create_dev_sd(&bpctl_dev_arr[idx_dev]); return NOTIFY_DONE; - } if (event == NETDEV_UNREGISTER) { int idx_dev = 0; @@ -5269,36 +5249,6 @@ int get_dev_idx_bsf(int bus, int slot, int func) return -1; } -static void str_low(char *str) -{ - int i; - - for (i = 0; i < strlen(str); i++) - if ((str[i] >= 65) && (str[i] <= 90)) - str[i] += 32; -} - -static unsigned long str_to_hex(char *p) -{ - unsigned long hex = 0; - unsigned long length = strlen(p), shift = 0; - unsigned char dig = 0; - - str_low(p); - length = strlen(p); - - if (length == 0) - return 0; - - do { - dig = p[--length]; - dig = dig < 'a' ? (dig - '0') : (dig - 'a' + 0xa); - hex |= (dig << shift); - shift += 4; - } while (length); - return hex; -} - static int get_dev_idx(int ifindex) { int idx_dev = 0; @@ -5329,70 +5279,26 @@ static struct bpctl_dev *get_dev_idx_p(int ifindex) static void if_scan_init(void) { - int idx_dev = 0; struct net_device *dev; - int ifindex; + /* rcu_read_lock(); */ /* rtnl_lock(); */ /* rcu_read_lock(); */ for_each_netdev(&init_net, dev) { + int idx_dev; - struct ethtool_drvinfo drvinfo; - char cbuf[32]; - char *buf = NULL; - char res[10]; - int i = 0; - int bus = 0, slot = 0, func = 0; - ifindex = dev->ifindex; - - memset(res, 0, 10); - memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); - - if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) { - memset(&drvinfo, 0, sizeof(drvinfo)); - dev->ethtool_ops->get_drvinfo(dev, &drvinfo); - } else + if (bp_get_dev_idx_bsf(dev, &idx_dev)) continue; - if (!strcmp(drvinfo.bus_info, "N/A")) - continue; - memcpy(&cbuf, drvinfo.bus_info, 32); - buf = &cbuf[0]; - while (*buf++ != ':') - ; - for (i = 0; i < 10; i++, buf++) { - if (*buf == ':') - break; - res[i] = *buf; - - } - buf++; - bus = str_to_hex(res); - memset(res, 0, 10); - - for (i = 0; i < 10; i++, buf++) { - if (*buf == '.') - break; - res[i] = *buf; - - } - buf++; - slot = str_to_hex(res); - func = str_to_hex(buf); - idx_dev = get_dev_idx_bsf(bus, slot, func); - - if (idx_dev != -1) { - - bpctl_dev_arr[idx_dev].ifindex = ifindex; - bpctl_dev_arr[idx_dev].ndev = dev; - - } + if (idx_dev == -1) + continue; + bpctl_dev_arr[idx_dev].ifindex = dev->ifindex; + bpctl_dev_arr[idx_dev].ndev = dev; } /* rtnl_unlock(); */ /* rcu_read_unlock(); */ - } static long device_ioctl(struct file *file, /* see include/linux/fs.h */ diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index 869dcd3b385a..b6eb5df7a426 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -791,8 +791,8 @@ static bool slic_mac_filter(struct adapter *adapter, struct mcast_address *mcaddr = adapter->mcastaddrs; while (mcaddr) { - if (!compare_ether_addr(mcaddr->address, - ether_frame->ether_dhost)) { + if (ether_addr_equal(mcaddr->address, + ether_frame->ether_dhost)) { adapter->rcv_multicasts++; netdev->stats.multicast++; return true; @@ -2333,7 +2333,7 @@ static int slic_mcast_add_list(struct adapter *adapter, char *address) /* Check to see if it already exists */ mlist = adapter->mcastaddrs; while (mlist) { - if (!compare_ether_addr(mlist->address, address)) + if (ether_addr_equal(mlist->address, address)) return 0; mlist = mlist->next; } diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c index 8add64b1cb09..ba199ffff178 100644 --- a/drivers/staging/sm7xxfb/sm7xxfb.c +++ b/drivers/staging/sm7xxfb/sm7xxfb.c @@ -130,7 +130,8 @@ static int __init sm7xx_vga_setup(char *options) for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { if (strstr(options, vesa_mode_table[i].index)) { smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width; - smtc_scr_info.lfb_height = vesa_mode_table[i].lfb_height; + smtc_scr_info.lfb_height = + vesa_mode_table[i].lfb_height; smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; return 0; } @@ -259,8 +260,7 @@ static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, if (sfb->fb.var.bits_per_pixel == 16) { u32 *pal = sfb->fb.pseudo_palette; val = chan_to_field(red, &sfb->fb.var.red); - val |= chan_to_field(green, \ - &sfb->fb.var.green); + val |= chan_to_field(green, &sfb->fb.var.green); val |= chan_to_field(blue, &sfb->fb.var.blue); #ifdef __BIG_ENDIAN pal[regno] = @@ -274,8 +274,7 @@ static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, } else { u32 *pal = sfb->fb.pseudo_palette; val = chan_to_field(red, &sfb->fb.var.red); - val |= chan_to_field(green, \ - &sfb->fb.var.green); + val |= chan_to_field(green, &sfb->fb.var.green); val |= chan_to_field(blue, &sfb->fb.var.blue); #ifdef __BIG_ENDIAN val = @@ -508,9 +507,9 @@ static void sm7xx_set_timing(struct smtcfb_info *sfb) /* init SEQ register SR30 - SR75 */ for (i = 0; i < SIZE_SR30_SR75; i++) - if (((i + 0x30) != 0x62) \ - && ((i + 0x30) != 0x6a) \ - && ((i + 0x30) != 0x6b)) + if ((i + 0x30) != 0x62 && + (i + 0x30) != 0x6a && + (i + 0x30) != 0x6b) smtc_seqw(i + 0x30, VGAMode[j].Init_SR30_SR75[i]); @@ -933,7 +932,6 @@ static void smtcfb_pci_remove(struct pci_dev *pdev) struct smtcfb_info *sfb; sfb = pci_get_drvdata(pdev); - pci_set_drvdata(pdev, NULL); smtc_unmap_smem(sfb); smtc_unmap_mmio(sfb); unregister_framebuffer(&sfb->fb); diff --git a/drivers/staging/speakup/Kconfig b/drivers/staging/speakup/Kconfig index 8c3e7a60a9be..efd6f4560d3e 100644 --- a/drivers/staging/speakup/Kconfig +++ b/drivers/staging/speakup/Kconfig @@ -51,6 +51,7 @@ config SPEAKUP_SYNTH_ACNTSA config SPEAKUP_SYNTH_ACNTPC tristate "Accent PC synthesizer support" + depends on ISA || COMPILE_TEST ---help--- This is the Speakup driver for the accent pc synthesizer. You can say y to build it into the kernel, @@ -102,6 +103,7 @@ config SPEAKUP_SYNTH_DECEXT config SPEAKUP_SYNTH_DECPC depends on m + depends on ISA || COMPILE_TEST tristate "DECtalk PC (big ISA card) synthesizer support" ---help--- @@ -124,6 +126,7 @@ config SPEAKUP_SYNTH_DECPC config SPEAKUP_SYNTH_DTLK tristate "DoubleTalk PC synthesizer support" + depends on ISA || COMPILE_TEST ---help--- This is the Speakup driver for the internal DoubleTalk @@ -134,6 +137,7 @@ config SPEAKUP_SYNTH_DTLK config SPEAKUP_SYNTH_KEYPC tristate "Keynote Gold PC synthesizer support" + depends on ISA || COMPILE_TEST ---help--- This is the Speakup driver for the Keynote Gold diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c index 51bdea3a5bea..f31afa2cffb7 100644 --- a/drivers/staging/speakup/kobjects.c +++ b/drivers/staging/speakup/kobjects.c @@ -586,6 +586,25 @@ ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr, EXPORT_SYMBOL_GPL(spk_var_show); /* + * Used to reset either default_pitch or default_vol. + */ +static inline void spk_reset_default_value(char *header_name, + int *synth_default_value, int idx) +{ + struct st_var_header *param; + + if (synth && synth_default_value) { + param = spk_var_header_by_name(header_name); + if (param) { + spk_set_num_var(synth_default_value[idx], + param, E_NEW_DEFAULT); + spk_set_num_var(0, param, E_DEFAULT); + pr_info("%s reset to default value\n", param->name); + } + } +} + +/* * This function is called when a user echos a value to one of the * variable parameters. */ @@ -624,56 +643,47 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr, if (ret == -ERANGE) { var_data = param->data; pr_warn("value for %s out of range, expect %d to %d\n", - attr->attr.name, + param->name, var_data->u.n.low, var_data->u.n.high); } + + /* + * If voice was just changed, we might need to reset our default + * pitch and volume. + */ + if (param->var_id == VOICE && synth && + (ret == 0 || ret == -ERESTART)) { + var_data = param->data; + value = var_data->u.n.value; + spk_reset_default_value("pitch", synth->default_pitch, + value); + spk_reset_default_value("vol", synth->default_vol, + value); + } break; case VAR_STRING: - len = strlen(buf); - if ((len >= 1) && (buf[len - 1] == '\n')) + len = strlen(cp); + if ((len >= 1) && (cp[len - 1] == '\n')) --len; - if ((len >= 2) && (buf[0] == '"') && (buf[len - 1] == '"')) { - ++buf; + if ((len >= 2) && (cp[0] == '"') && (cp[len - 1] == '"')) { + ++cp; len -= 2; } - cp = (char *) buf; cp[len] = '\0'; - ret = spk_set_string_var(buf, param, len); + ret = spk_set_string_var(cp, param, len); if (ret == -E2BIG) pr_warn("value too long for %s\n", - attr->attr.name); + param->name); break; default: pr_warn("%s unknown type %d\n", param->name, (int)param->var_type); break; } - /* - * If voice was just changed, we might need to reset our default - * pitch and volume. - */ - if (strcmp(attr->attr.name, "voice") == 0) { - if (synth && synth->default_pitch) { - param = spk_var_header_by_name("pitch"); - if (param) { - spk_set_num_var(synth->default_pitch[value], - param, E_NEW_DEFAULT); - spk_set_num_var(0, param, E_DEFAULT); - } - } - if (synth && synth->default_vol) { - param = spk_var_header_by_name("vol"); - if (param) { - spk_set_num_var(synth->default_vol[value], - param, E_NEW_DEFAULT); - spk_set_num_var(0, param, E_DEFAULT); - } - } - } spin_unlock_irqrestore(&speakup_info.spinlock, flags); if (ret == -ERESTART) - pr_info("%s reset to default value\n", attr->attr.name); + pr_info("%s reset to default value\n", param->name); return count; } EXPORT_SYMBOL_GPL(spk_var_store); diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c index 14079c4949a8..47502fa5f3f6 100644 --- a/drivers/staging/speakup/main.c +++ b/drivers/staging/speakup/main.c @@ -90,7 +90,7 @@ const struct st_bits_data spk_punc_info[] = { {"repeats", "()", CH_RPT}, {"extended numeric", "", B_EXNUM}, {"symbols", "", B_SYM}, - {0, 0} + {NULL, NULL} }; static char mark_cut_flag; diff --git a/drivers/staging/speakup/speakup_acntpc.c b/drivers/staging/speakup/speakup_acntpc.c index 80141aca712f..1c8a7f4a0ef5 100644 --- a/drivers/staging/speakup/speakup_acntpc.c +++ b/drivers/staging/speakup/speakup_acntpc.c @@ -223,7 +223,7 @@ static void do_catch_up(struct spk_synth *synth) if (ch == '\n') ch = PROCSPEECH; outb_p(ch, speakup_info.port_tts); - if (jiffies >= jiff_max && ch == SPACE) { + if (time_after_eq(jiffies, jiff_max) && ch == SPACE) { timeout = SPK_XMITR_TIMEOUT; while (synth_writable()) { if (!--timeout) diff --git a/drivers/staging/speakup/speakup_apollo.c b/drivers/staging/speakup/speakup_apollo.c index 95d3132f0a35..70cf1591676a 100644 --- a/drivers/staging/speakup/speakup_apollo.c +++ b/drivers/staging/speakup/speakup_apollo.c @@ -179,7 +179,7 @@ static void do_catch_up(struct spk_synth *synth) schedule_timeout(msecs_to_jiffies(full_time_val)); continue; } - if ((jiffies >= jiff_max) && (ch == SPACE)) { + if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) { spin_lock_irqsave(&speakup_info.spinlock, flags); jiffy_delta_val = jiffy_delta->u.n.value; full_time_val = full_time->u.n.value; diff --git a/drivers/staging/speakup/speakup_audptr.c b/drivers/staging/speakup/speakup_audptr.c index 3508aee98ab0..61a3ceeb0d3a 100644 --- a/drivers/staging/speakup/speakup_audptr.c +++ b/drivers/staging/speakup/speakup_audptr.c @@ -39,7 +39,7 @@ static struct var_t vars[] = { { RATE, .u.n = {"\x05[r%d]", 10, 0, 20, 100, -10, NULL } }, { PITCH, .u.n = {"\x05[f%d]", 80, 39, 4500, 0, 0, NULL } }, { VOL, .u.n = {"\x05[g%d]", 21, 0, 40, 0, 0, NULL } }, - { TONE, .u.n = {"\x05[s%d]", 9, 0, 63, 0, 0, 0 } }, + { TONE, .u.n = {"\x05[s%d]", 9, 0, 63, 0, 0, NULL } }, { PUNCT, .u.n = {"\x05[A%c]", 0, 0, 3, 0, 0, "nmsa" } }, { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } }, V_LAST_VAR diff --git a/drivers/staging/speakup/varhandlers.c b/drivers/staging/speakup/varhandlers.c index 9aa2a78cd71c..445a3fda380e 100644 --- a/drivers/staging/speakup/varhandlers.c +++ b/drivers/staging/speakup/varhandlers.c @@ -46,7 +46,7 @@ static struct st_var_header var_headers[] = { { "direct", DIRECT, VAR_NUM, NULL, NULL }, }; -static struct st_var_header *var_ptrs[MAXVARS] = { 0, 0, 0 }; +static struct st_var_header *var_ptrs[MAXVARS] = { NULL, NULL, NULL }; static struct punc_var_t punc_vars[] = { { PUNC_SOME, 1 }, @@ -280,7 +280,7 @@ int spk_set_mask_bits(const char *input, const int which, const int how) if (!cp) cp = spk_punc_info[which].value; else { - for ( ; *cp; cp++) { + for (; *cp; cp++) { if (*cp < SPACE) break; if (mask < PUNC) { @@ -294,11 +294,11 @@ int spk_set_mask_bits(const char *input, const int which, const int how) cp = (u_char *)input; } if (how&2) { - for ( ; *cp; cp++) + for (; *cp; cp++) if (*cp > SPACE) spk_chartab[*cp] |= mask; } else { - for ( ; *cp; cp++) + for (; *cp; cp++) if (*cp > SPACE) spk_chartab[*cp] &= ~mask; } diff --git a/drivers/staging/tidspbridge/rmgr/dspdrv.c b/drivers/staging/tidspbridge/rmgr/dspdrv.c index d460f5823c6b..012e4a38d2db 100644 --- a/drivers/staging/tidspbridge/rmgr/dspdrv.c +++ b/drivers/staging/tidspbridge/rmgr/dspdrv.c @@ -36,7 +36,7 @@ /* * ======== dsp_init ======== - * Allocates bridge resources. Loads a base image onto DSP, if specified. + * Allocates bridge resources. Loads a base image onto DSP, if specified. */ u32 dsp_init(u32 *init_status) { @@ -106,7 +106,7 @@ func_cont: /* * ======== dsp_deinit ======== - * Frees the resources allocated for bridge. + * Frees the resources allocated for bridge. */ bool dsp_deinit(u32 device_context) { diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index d8957a556626..76a1ff0e6275 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -357,8 +357,9 @@ static int stub_probe(struct usb_interface *interface, busid_priv = get_busid_priv(udev_busid); if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) || (busid_priv->status == STUB_BUSID_OTHER)) { - dev_info(&interface->dev, "%s is not in match_busid table... " - "skip!\n", udev_busid); + dev_info(&interface->dev, + "%s is not in match_busid table... skip!\n", + udev_busid); /* * Return value should be ENODEV or ENOXIO to continue trying @@ -375,8 +376,10 @@ static int stub_probe(struct usb_interface *interface, } if (!strcmp(udev->bus->bus_name, "vhci_hcd")) { - dev_dbg(&udev->dev, "%s is attached on vhci_hcd... skip!\n", - udev_busid); + dev_dbg(&udev->dev, + "%s is attached on vhci_hcd... skip!\n", + udev_busid); + return -ENODEV; } @@ -386,10 +389,10 @@ static int stub_probe(struct usb_interface *interface, return -ENODEV; busid_priv->interf_count++; - dev_info(&interface->dev, "usbip-host: register new interface " - "(bus %u dev %u ifn %u)\n", - udev->bus->busnum, udev->devnum, - interface->cur_altsetting->desc.bInterfaceNumber); + dev_info(&interface->dev, + "usbip-host: register new interface (bus %u dev %u ifn %u)\n", + udev->bus->busnum, udev->devnum, + interface->cur_altsetting->desc.bInterfaceNumber); /* set private data to usb_interface */ usb_set_intfdata(interface, sdev); @@ -412,9 +415,10 @@ static int stub_probe(struct usb_interface *interface, if (!sdev) return -ENOMEM; - dev_info(&interface->dev, "usbip-host: register new device " - "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum, - interface->cur_altsetting->desc.bInterfaceNumber); + dev_info(&interface->dev, + "usbip-host: register new device (bus %u dev %u ifn %u)\n", + udev->bus->busnum, udev->devnum, + interface->cur_altsetting->desc.bInterfaceNumber); busid_priv->interf_count = 0; busid_priv->shutdown_busid = 0; diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c index 33027cce6700..baf857f7cc88 100644 --- a/drivers/staging/usbip/stub_main.c +++ b/drivers/staging/usbip/stub_main.c @@ -255,14 +255,14 @@ static int __init usbip_host_init(void) } ret = usb_register(&stub_driver); - if (ret < 0) { + if (ret) { pr_err("usb_register failed %d\n", ret); goto err_usb_register; } ret = driver_create_file(&stub_driver.drvwrap.driver, &driver_attr_match_busid); - if (ret < 0) { + if (ret) { pr_err("driver_create_file failed\n"); goto err_create_file; } diff --git a/drivers/staging/usbip/userspace/configure.ac b/drivers/staging/usbip/userspace/configure.ac index 2be4060f9036..0ee5d9263996 100644 --- a/drivers/staging/usbip/userspace/configure.ac +++ b/drivers/staging/usbip/userspace/configure.ac @@ -70,7 +70,6 @@ AC_ARG_WITH([tcp-wrappers], [AC_MSG_RESULT([not found]); exit 1]) else AC_MSG_RESULT([no]); - LIBS="$saved_LIBS" fi], dnl [ACTION-IF-NOT-GIVEN] [AC_MSG_RESULT([(default)]) diff --git a/drivers/staging/usbip/userspace/doc/usbip.8 b/drivers/staging/usbip/userspace/doc/usbip.8 index ccdadc87c478..a6097be25d28 100644 --- a/drivers/staging/usbip/userspace/doc/usbip.8 +++ b/drivers/staging/usbip/userspace/doc/usbip.8 @@ -3,7 +3,7 @@ usbip \- manage USB/IP devices .SH SYNOPSIS .B usbip -[\foptions\R] <\fIcommand\fR> <\fIargs\fR> +[\fIoptions\fR] <\fIcommand\fR> <\fIargs\fR> .SH DESCRIPTION On a USB/IP server, devices can be listed, bound, and unbound using @@ -23,6 +23,12 @@ Print debugging information. Log to syslog. .PP +.HP +\fB\-\-tcp-port PORT\fR +.IP +Connect to PORT on remote host (used for attach and list --remote). +.PP + .SH COMMANDS .HP \fBversion\fR diff --git a/drivers/staging/usbip/userspace/doc/usbipd.8 b/drivers/staging/usbip/userspace/doc/usbipd.8 index d896936f1780..ac4635db3f03 100644 --- a/drivers/staging/usbip/userspace/doc/usbipd.8 +++ b/drivers/staging/usbip/userspace/doc/usbipd.8 @@ -14,10 +14,22 @@ Devices have to explicitly be exported using before usbipd makes them available to other hosts. The daemon accepts connections from USB/IP clients -on TCP port 3240. +on TCP port 3240 by default. .SH OPTIONS .HP +\fB\-4\fR, \fB\-\-ipv4\fR +.IP +Bind to IPv4. Default is both. +.PP + +.HP +\fB\-6\fR, \fB\-\-ipv6\fR +.IP +Bind to IPv6. Default is both. +.PP + +.HP \fB\-D\fR, \fB\-\-daemon\fR .IP Run as a daemon process. @@ -29,6 +41,19 @@ Run as a daemon process. Print debugging information. .PP +.HP +\fB\-PFILE\fR, \fB\-\-pid FILE\fR +.IP +Write process id to FILE. +.br +If no FILE specified, use /var/run/usbipd.pid +.PP + +\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR +.IP +Listen on TCP/IP port PORT. +.PP + \fB\-h\fR, \fB\-\-help\fR .IP Print the program help message and exit. diff --git a/drivers/staging/usbip/userspace/src/usbip_network.c b/drivers/staging/usbip/userspace/src/usbip_network.c index c39a07f1d38c..b4c37e76a6e0 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.c +++ b/drivers/staging/usbip/userspace/src/usbip_network.c @@ -25,6 +25,10 @@ #include <netinet/tcp.h> #include <unistd.h> +#ifdef HAVE_LIBWRAP +#include <tcpd.h> +#endif + #include "usbip_common.h" #include "usbip_network.h" @@ -239,6 +243,18 @@ int usbip_net_set_keepalive(int sockfd) return ret; } +int usbip_net_set_v6only(int sockfd) +{ + const int val = 1; + int ret; + + ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); + if (ret < 0) + dbg("setsockopt: IPV6_V6ONLY"); + + return ret; +} + /* * IPv6 Ready */ diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h index 2d0e4277b62b..f19ae19799b4 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.h +++ b/drivers/staging/usbip/userspace/src/usbip_network.h @@ -180,6 +180,7 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code); int usbip_net_set_reuseaddr(int sockfd); int usbip_net_set_nodelay(int sockfd); int usbip_net_set_keepalive(int sockfd); +int usbip_net_set_v6only(int sockfd); int usbip_net_tcp_connect(char *hostname, char *port); #endif /* __USBIP_NETWORK_H */ diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c index 1c76cfd274d0..7980f8b5517b 100644 --- a/drivers/staging/usbip/userspace/src/usbipd.c +++ b/drivers/staging/usbip/userspace/src/usbipd.c @@ -56,6 +56,13 @@ static const char usbip_version_string[] = PACKAGE_STRING; static const char usbipd_help_string[] = "usage: usbipd [options]\n" + "\n" + " -4, --ipv4\n" + " Bind to IPv4. Default is both.\n" + "\n" + " -6, --ipv6\n" + " Bind to IPv6. Default is both.\n" + "\n" " -D, --daemon\n" " Run as a daemon process.\n" "\n" @@ -354,14 +361,15 @@ static void addrinfo_to_text(struct addrinfo *ai, char buf[], snprintf(buf, buf_size, "%s:%s", hbuf, sbuf); } -static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[]) +static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[], + int maxsockfd) { struct addrinfo *ai; int ret, nsockfd = 0; const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2; char ai_buf[ai_buf_size]; - for (ai = ai_head; ai && nsockfd < MAXSOCKFD; ai = ai->ai_next) { + for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) { int sock; addrinfo_to_text(ai, ai_buf, ai_buf_size); dbg("opening %s", ai_buf); @@ -374,6 +382,9 @@ static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[]) usbip_net_set_reuseaddr(sock); usbip_net_set_nodelay(sock); + /* We use seperate sockets for IPv4 and IPv6 + * (see do_standalone_mode()) */ + usbip_net_set_v6only(sock); if (sock >= FD_SETSIZE) { err("FD_SETSIZE: %s: sock=%d, max=%d", @@ -402,11 +413,6 @@ static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[]) sockfdlist[nsockfd++] = sock; } - if (nsockfd == 0) - return -1; - - dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); - return nsockfd; } @@ -473,11 +479,11 @@ static void remove_pid_file() } } -static int do_standalone_mode(int daemonize) +static int do_standalone_mode(int daemonize, int ipv4, int ipv6) { struct addrinfo *ai_head; int sockfdlist[MAXSOCKFD]; - int nsockfd; + int nsockfd, family; int i, terminate; struct pollfd *fds; struct timespec timeout; @@ -501,21 +507,36 @@ static int do_standalone_mode(int daemonize) set_signal(); write_pid_file(); - ai_head = do_getaddrinfo(NULL, PF_UNSPEC); + info("starting " PROGNAME " (%s)", usbip_version_string); + + /* + * To suppress warnings on systems with bindv6only disabled + * (default), we use seperate sockets for IPv6 and IPv4 and set + * IPV6_V6ONLY on the IPv6 sockets. + */ + if (ipv4 && ipv6) + family = AF_UNSPEC; + else if (ipv4) + family = AF_INET; + else + family = AF_INET6; + + ai_head = do_getaddrinfo(NULL, family); if (!ai_head) { usbip_host_driver_close(); return -1; } - - info("starting " PROGNAME " (%s)", usbip_version_string); - - nsockfd = listen_all_addrinfo(ai_head, sockfdlist); + nsockfd = listen_all_addrinfo(ai_head, sockfdlist, + sizeof(sockfdlist) / sizeof(*sockfdlist)); + freeaddrinfo(ai_head); if (nsockfd <= 0) { err("failed to open a listening socket"); - freeaddrinfo(ai_head); usbip_host_driver_close(); return -1; } + + dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); + fds = calloc(nsockfd, sizeof(struct pollfd)); for (i = 0; i < nsockfd; i++) { fds[i].fd = sockfdlist[i]; @@ -551,7 +572,6 @@ static int do_standalone_mode(int daemonize) info("shutting down " PROGNAME); free(fds); - freeaddrinfo(ai_head); usbip_host_driver_close(); return 0; @@ -560,6 +580,9 @@ static int do_standalone_mode(int daemonize) int main(int argc, char *argv[]) { static const struct option longopts[] = { + { "ipv4", no_argument, NULL, '4' }, + { "ipv6", no_argument, NULL, '6' }, + { "daemon", no_argument, NULL, 'D' }, { "daemon", no_argument, NULL, 'D' }, { "debug", no_argument, NULL, 'd' }, { "pid", optional_argument, NULL, 'P' }, @@ -576,6 +599,7 @@ int main(int argc, char *argv[]) } cmd; int daemonize = 0; + int ipv4 = 0, ipv6 = 0; int opt, rc = -1; pid_file = NULL; @@ -587,12 +611,18 @@ int main(int argc, char *argv[]) cmd = cmd_standalone_mode; for (;;) { - opt = getopt_long(argc, argv, "DdP::t:hv", longopts, NULL); + opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL); if (opt == -1) break; switch (opt) { + case '4': + ipv4 = 1; + break; + case '6': + ipv6 = 1; + break; case 'D': daemonize = 1; break; @@ -618,9 +648,12 @@ int main(int argc, char *argv[]) } } + if (!ipv4 && !ipv6) + ipv4 = ipv6 = 1; + switch (cmd) { case cmd_standalone_mode: - rc = do_standalone_mode(daemonize); + rc = do_standalone_mode(daemonize, ipv4, ipv6); remove_pid_file(); break; case cmd_version: diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index d7974cb2cc6f..e810ad53e2ac 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -999,12 +999,6 @@ static int vhci_hcd_probe(struct platform_device *pdev) usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id); - /* will be removed */ - if (pdev->dev.dma_mask) { - dev_info(&pdev->dev, "vhci_hcd DMA not supported\n"); - return -EINVAL; - } - /* * Allocate and initialize hcd. * Our private data is also allocated automatically. @@ -1146,11 +1140,11 @@ static int __init vhci_hcd_init(void) return -ENODEV; ret = platform_driver_register(&vhci_driver); - if (ret < 0) + if (ret) goto err_driver_register; ret = platform_device_register(&the_pdev); - if (ret < 0) + if (ret) goto err_platform_device_register; pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); diff --git a/drivers/staging/vt6655/80211mgr.c b/drivers/staging/vt6655/80211mgr.c index 76c8490b0734..7949d58ad7d1 100644 --- a/drivers/staging/vt6655/80211mgr.c +++ b/drivers/staging/vt6655/80211mgr.c @@ -165,9 +165,8 @@ vMgrDecodeBeacon( break; case WLAN_EID_RSN: - if (pFrame->pRSN == NULL) { + if (pFrame->pRSN == NULL) pFrame->pRSN = (PWLAN_IE_RSN)pItem; - } break; case WLAN_EID_RSN_WPA: if (pFrame->pRSNWPA == NULL) { @@ -382,9 +381,8 @@ vMgrDecodeAssocRequest( break; case WLAN_EID_RSN: - if (pFrame->pRSN == NULL) { + if (pFrame->pRSN == NULL) pFrame->pRSN = (PWLAN_IE_RSN)pItem; - } break; case WLAN_EID_RSN_WPA: if (pFrame->pRSNWPA == NULL) { @@ -556,9 +554,8 @@ vMgrDecodeReassocRequest( break; case WLAN_EID_RSN: - if (pFrame->pRSN == NULL) { + if (pFrame->pRSN == NULL) pFrame->pRSN = (PWLAN_IE_RSN)pItem; - } break; case WLAN_EID_RSN_WPA: if (pFrame->pRSNWPA == NULL) { @@ -742,9 +739,8 @@ vMgrDecodeProbeResponse( break; case WLAN_EID_RSN: - if (pFrame->pRSN == NULL) { + if (pFrame->pRSN == NULL) pFrame->pRSN = (PWLAN_IE_RSN)pItem; - } break; case WLAN_EID_RSN_WPA: if (pFrame->pRSNWPA == NULL) { @@ -858,9 +854,9 @@ vMgrDecodeAuthen( pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + WLAN_AUTHEN_OFF_CHALLENGE); - if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE)) { + if (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len) && + pItem->byElementID == WLAN_EID_CHALLENGE) pFrame->pChallenge = (PWLAN_IE_CHALLENGE)pItem; - } return; } diff --git a/drivers/staging/vt6655/aes_ccmp.c b/drivers/staging/vt6655/aes_ccmp.c index fc056fc61995..82b0bd1c056a 100644 --- a/drivers/staging/vt6655/aes_ccmp.c +++ b/drivers/staging/vt6655/aes_ccmp.c @@ -46,7 +46,7 @@ * SBOX Table */ -unsigned char sbox_table[256] = +static unsigned char sbox_table[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, @@ -66,7 +66,7 @@ unsigned char sbox_table[256] = 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; -unsigned char dot2_table[256] = { +static unsigned char dot2_table[256] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, @@ -85,7 +85,7 @@ unsigned char dot2_table[256] = { 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 }; -unsigned char dot3_table[256] = { +static unsigned char dot3_table[256] = { 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, @@ -110,7 +110,7 @@ unsigned char dot3_table[256] = { /*--------------------- Export Functions --------------------------*/ -void xor_128(unsigned char *a, unsigned char *b, unsigned char *out) +static void xor_128(unsigned char *a, unsigned char *b, unsigned char *out) { unsigned long *dwPtrA = (unsigned long *)a; unsigned long *dwPtrB = (unsigned long *)b; @@ -122,7 +122,7 @@ void xor_128(unsigned char *a, unsigned char *b, unsigned char *out) (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++); } -void xor_32(unsigned char *a, unsigned char *b, unsigned char *out) +static void xor_32(unsigned char *a, unsigned char *b, unsigned char *out) { unsigned long *dwPtrA = (unsigned long *)a; unsigned long *dwPtrB = (unsigned long *)b; @@ -131,7 +131,7 @@ void xor_32(unsigned char *a, unsigned char *b, unsigned char *out) (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++); } -void AddRoundKey(unsigned char *key, int round) +static void AddRoundKey(unsigned char *key, int round) { unsigned char sbox_key[4]; unsigned char rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; @@ -149,7 +149,7 @@ void AddRoundKey(unsigned char *key, int round) xor_32(&key[12], &key[8], &key[12]); } -void SubBytes(unsigned char *in, unsigned char *out) +static void SubBytes(unsigned char *in, unsigned char *out) { int i; @@ -158,7 +158,7 @@ void SubBytes(unsigned char *in, unsigned char *out) } } -void ShiftRows(unsigned char *in, unsigned char *out) +static void ShiftRows(unsigned char *in, unsigned char *out) { out[0] = in[0]; out[1] = in[5]; @@ -178,7 +178,7 @@ void ShiftRows(unsigned char *in, unsigned char *out) out[15] = in[11]; } -void MixColumns(unsigned char *in, unsigned char *out) +static void MixColumns(unsigned char *in, unsigned char *out) { out[0] = dot2_table[in[0]] ^ dot3_table[in[1]] ^ in[2] ^ in[3]; out[1] = in[0] ^ dot2_table[in[1]] ^ dot3_table[in[2]] ^ in[3]; @@ -186,7 +186,7 @@ void MixColumns(unsigned char *in, unsigned char *out) out[3] = dot3_table[in[0]] ^ in[1] ^ in[2] ^ dot2_table[in[3]]; } -void AESv128(unsigned char *key, unsigned char *data, unsigned char *ciphertext) +static void AESv128(unsigned char *key, unsigned char *data, unsigned char *ciphertext) { int i; int round; diff --git a/drivers/staging/vt6655/bssdb.c b/drivers/staging/vt6655/bssdb.c index f983915168b7..a23b591eeac3 100644 --- a/drivers/staging/vt6655/bssdb.c +++ b/drivers/staging/vt6655/bssdb.c @@ -148,7 +148,8 @@ BSSpSearchBSSList( if (pDevice->bLinkPass == false) pCurrBSS->bSelected = false; if ((pCurrBSS->bActive) && (pCurrBSS->bSelected == false)) { - if (!compare_ether_addr(pCurrBSS->abyBSSID, pbyBSSID)) { + if (ether_addr_equal(pCurrBSS->abyBSSID, + pbyBSSID)) { if (pSSID != NULL) { // compare ssid if (!memcmp(pSSID->abySSID, @@ -275,7 +276,8 @@ BSSvClearBSSList( for (ii = 0; ii < MAX_BSS_NUM; ii++) { if (bKeepCurrBSSID) { if (pMgmt->sBSSList[ii].bActive && - !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyCurrBSSID)) { + ether_addr_equal(pMgmt->sBSSList[ii].abyBSSID, + pMgmt->abyCurrBSSID)) { // bKeepCurrBSSID = false; continue; } @@ -318,7 +320,7 @@ BSSpAddrIsInBSSList( for (ii = 0; ii < MAX_BSS_NUM; ii++) { pBSSList = &(pMgmt->sBSSList[ii]); if (pBSSList->bActive) { - if (!compare_ether_addr(pBSSList->abyBSSID, abyBSSID)) { + if (ether_addr_equal(pBSSList->abyBSSID, abyBSSID)) { if (pSSID->len == ((PWLAN_IE_SSID)pBSSList->abySSID)->len) { if (memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pBSSList->abySSID)->abySSID, @@ -733,7 +735,8 @@ BSSDBbIsSTAInNodeDB(void *pMgmtObject, unsigned char *abyDstAddr, // Index = 0 reserved for AP Node for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) { if (pMgmt->sNodeDBTable[ii].bActive) { - if (!compare_ether_addr(abyDstAddr, pMgmt->sNodeDBTable[ii].abyMACAddr)) { + if (ether_addr_equal(abyDstAddr, + pMgmt->sNodeDBTable[ii].abyMACAddr)) { *puNodeIndex = ii; return true; } diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 7f36a7103c3e..e93fdc88d844 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1153,10 +1153,6 @@ static void device_free_info(PSDevice pDevice) { pci_release_regions(pDevice->pcid); if (dev) free_netdev(dev); - - if (pDevice->pcid) { - pci_set_drvdata(pDevice->pcid, NULL); - } } static bool device_init_rings(PSDevice pDevice) { diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c index a9533f3f2529..0ff51cb4a207 100644 --- a/drivers/staging/vt6655/dpc.c +++ b/drivers/staging/vt6655/dpc.c @@ -172,9 +172,9 @@ s_vProcessRxMACHeader(PSDevice pDevice, unsigned char *pbyRxBufferAddr, }; pbyRxBuffer = (unsigned char *)(pbyRxBufferAddr + cbHeaderSize); - if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) { + if (ether_addr_equal(pbyRxBuffer, pDevice->abySNAP_Bridgetunnel)) { cbHeaderSize += 6; - } else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) { + } else if (ether_addr_equal(pbyRxBuffer, pDevice->abySNAP_RFC1042)) { cbHeaderSize += 6; pwType = (unsigned short *)(pbyRxBufferAddr + cbHeaderSize); if ((*pwType != TYPE_PKT_IPX) && (*pwType != cpu_to_le16(0xF380))) { @@ -420,7 +420,8 @@ device_receive_frame( s_vGetDASA(skb->data+4, &cbHeaderSize, &pDevice->sRxEthHeader); // filter packet send from myself - if (!compare_ether_addr((unsigned char *)&(pDevice->sRxEthHeader.abySrcAddr[0]), pDevice->abyCurrentNetAddr)) + if (ether_addr_equal(pDevice->sRxEthHeader.abySrcAddr, + pDevice->abyCurrentNetAddr)) return false; if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) { diff --git a/drivers/staging/vt6655/hostap.c b/drivers/staging/vt6655/hostap.c index 8acff44a9e75..aab0012bba92 100644 --- a/drivers/staging/vt6655/hostap.c +++ b/drivers/staging/vt6655/hostap.c @@ -720,7 +720,6 @@ static int hostap_get_encryption(PSDevice pDevice, * Return Value: * */ - int vt6655_hostap_ioctl(PSDevice pDevice, struct iw_point *p) { struct viawget_hostapd_param *param; @@ -731,7 +730,7 @@ int vt6655_hostap_ioctl(PSDevice pDevice, struct iw_point *p) p->length > VIAWGET_HOSTAPD_MAX_BUF_SIZE || !p->pointer) return -EINVAL; - param = kmalloc((int)p->length, (int)GFP_KERNEL); + param = kmalloc((int)p->length, GFP_KERNEL); if (param == NULL) return -ENOMEM; @@ -755,8 +754,8 @@ int vt6655_hostap_ioctl(PSDevice pDevice, struct iw_point *p) break; case VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR \n"); - return -EOPNOTSUPP; - break; + ret = -EOPNOTSUPP; + goto out; case VIAWGET_HOSTAPD_FLUSH: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_FLUSH \n"); spin_lock_irq(&pDevice->lock); @@ -790,40 +789,36 @@ int vt6655_hostap_ioctl(PSDevice pDevice, struct iw_point *p) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_FLAGS_STA \n"); ret = hostap_set_flags_sta(pDevice, param); break; - case VIAWGET_HOSTAPD_MLME: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_MLME \n"); - return -EOPNOTSUPP; - + ret = -EOPNOTSUPP; + goto out; case VIAWGET_HOSTAPD_SET_GENERIC_ELEMENT: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_GENERIC_ELEMENT \n"); ret = hostap_set_generic_element(pDevice, param); break; - case VIAWGET_HOSTAPD_SCAN_REQ: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SCAN_REQ \n"); - return -EOPNOTSUPP; - + ret = -EOPNOTSUPP; + goto out; case VIAWGET_HOSTAPD_STA_CLEAR_STATS: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_STA_CLEAR_STATS \n"); - return -EOPNOTSUPP; - + ret = -EOPNOTSUPP; + goto out; default: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vt6655_hostap_ioctl: unknown cmd=%d\n", (int)param->cmd); - return -EOPNOTSUPP; - break; + ret = -EOPNOTSUPP; + goto out; } if ((ret == 0) && ap_ioctl) { if (copy_to_user(p->pointer, param, p->length)) { ret = -EFAULT; - goto out; } } out: kfree(param); - return ret; } diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c index 9de698ef25f5..4bff8aa96be7 100644 --- a/drivers/staging/vt6655/iwctl.c +++ b/drivers/staging/vt6655/iwctl.c @@ -663,7 +663,8 @@ int iwctl_siwap(struct net_device *dev, unsigned int ii, uSameBssidNum = 0; for (ii = 0; ii < MAX_BSS_NUM; ii++) { if (pMgmt->sBSSList[ii].bActive && - !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyDesireBSSID)) { + ether_addr_equal(pMgmt->sBSSList[ii].abyBSSID, + pMgmt->abyDesireBSSID)) { uSameBssidNum++; } } @@ -840,7 +841,8 @@ int iwctl_siwessid(struct net_device *dev, // by means of judging if there are two same BSSID exist in list ? for (ii = 0; ii < MAX_BSS_NUM; ii++) { if (pMgmt->sBSSList[ii].bActive && - !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) { + ether_addr_equal(pMgmt->sBSSList[ii].abyBSSID, + pCurr->abyBSSID)) { uSameBssidNum++; } } diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c index 92b84b5ea115..04c1304d16e5 100644 --- a/drivers/staging/vt6655/key.c +++ b/drivers/staging/vt6655/key.c @@ -141,7 +141,7 @@ bool KeybGetKey( *pKey = NULL; for (i = 0; i < MAX_KEY_TABLE; i++) { if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { if (dwKeyIndex == 0xFFFFFFFF) { if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) { *pKey = &(pTable->KeyTable[i].PairwiseKey); @@ -208,7 +208,7 @@ bool KeybSetKey( j = i; } if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { // found table already exist if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key @@ -385,7 +385,7 @@ bool KeybRemoveKey( for (i = 0; i < MAX_KEY_TABLE; i++) { if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { if ((dwKeyIndex & PAIRWISE_KEY) != 0) { pTable->KeyTable[i].PairwiseKey.bKeyValid = false; s_vCheckKeyTableValid(pTable, dwIoBase); @@ -429,7 +429,7 @@ bool KeybRemoveAllKey( for (i = 0; i < MAX_KEY_TABLE; i++) { if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { pTable->KeyTable[i].PairwiseKey.bKeyValid = false; for (u = 0; u < MAX_GROUP_KEY; u++) { pTable->KeyTable[i].GroupKey[u].bKeyValid = false; @@ -512,7 +512,7 @@ bool KeybGetTransmitKey( *pKey = NULL; for (i = 0; i < MAX_KEY_TABLE; i++) { if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { if (dwKeyType == PAIRWISE_KEY) { if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) { *pKey = &(pTable->KeyTable[i].PairwiseKey); diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index 6948984a25ab..ce173cc16c19 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -55,7 +55,7 @@ /*--------------------- Static Variables --------------------------*/ -const unsigned long dwAL2230InitTable[CB_AL2230_INIT_SEQ] = { +static const unsigned long dwAL2230InitTable[CB_AL2230_INIT_SEQ] = { 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // 0x01A00200+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // @@ -73,7 +73,7 @@ const unsigned long dwAL2230InitTable[CB_AL2230_INIT_SEQ] = { 0x00580F00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW }; -const unsigned long dwAL2230ChannelTable0[CB_MAX_CHANNEL] = { +static const unsigned long dwAL2230ChannelTable0[CB_MAX_CHANNEL] = { 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz @@ -90,7 +90,7 @@ const unsigned long dwAL2230ChannelTable0[CB_MAX_CHANNEL] = { 0x03E7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M }; -const unsigned long dwAL2230ChannelTable1[CB_MAX_CHANNEL] = { +static const unsigned long dwAL2230ChannelTable1[CB_MAX_CHANNEL] = { 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz @@ -107,7 +107,7 @@ const unsigned long dwAL2230ChannelTable1[CB_MAX_CHANNEL] = { 0x06666100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M }; -unsigned long dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = { +static unsigned long dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = { 0x04040900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, 0x04041900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, 0x04042900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, @@ -177,7 +177,7 @@ unsigned long dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = { //{{ RobertYu:20050104 // 40MHz reference frequency // Need to Pull PLLON(PE3) low when writing channel registers through 3-wire. -const unsigned long dwAL7230InitTable[CB_AL7230_INIT_SEQ] = { +static const unsigned long dwAL7230InitTable[CB_AL7230_INIT_SEQ] = { 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a 0x841FF200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 451FE2 @@ -200,7 +200,7 @@ const unsigned long dwAL7230InitTable[CB_AL7230_INIT_SEQ] = { 0x1ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11a: 12BACF }; -const unsigned long dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = { +static const unsigned long dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = { 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g 0x451FE200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g @@ -219,7 +219,7 @@ const unsigned long dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = { 0x12BACF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11b/g }; -const unsigned long dwAL7230ChannelTable0[CB_MAX_CHANNEL] = { +static const unsigned long dwAL7230ChannelTable0[CB_MAX_CHANNEL] = { 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz @@ -285,7 +285,7 @@ const unsigned long dwAL7230ChannelTable0[CB_MAX_CHANNEL] = { 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56) }; -const unsigned long dwAL7230ChannelTable1[CB_MAX_CHANNEL] = { +static const unsigned long dwAL7230ChannelTable1[CB_MAX_CHANNEL] = { 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz @@ -349,7 +349,7 @@ const unsigned long dwAL7230ChannelTable1[CB_MAX_CHANNEL] = { 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56) }; -const unsigned long dwAL7230ChannelTable2[CB_MAX_CHANNEL] = { +static const unsigned long dwAL7230ChannelTable2[CB_MAX_CHANNEL] = { 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz @@ -428,7 +428,7 @@ const unsigned long dwAL7230ChannelTable2[CB_MAX_CHANNEL] = { * Return Value: true if succeeded; false if failed. * */ -bool s_bAL7230Init(unsigned long dwIoBase) +static bool s_bAL7230Init(unsigned long dwIoBase) { int ii; bool bResult; @@ -471,7 +471,7 @@ bool s_bAL7230Init(unsigned long dwIoBase) } // Need to Pull PLLON low when writing channel registers through 3-wire interface -bool s_bAL7230SelectChannel(unsigned long dwIoBase, unsigned char byChannel) +static bool s_bAL7230SelectChannel(unsigned long dwIoBase, unsigned char byChannel) { bool bResult; @@ -631,7 +631,7 @@ bool IFRFbWriteEmbedded(unsigned long dwIoBase, unsigned long dwData) * Return Value: true if succeeded; false if failed. * */ -bool RFbAL2230Init(unsigned long dwIoBase) +static bool RFbAL2230Init(unsigned long dwIoBase) { int ii; bool bResult; @@ -678,7 +678,7 @@ bool RFbAL2230Init(unsigned long dwIoBase) return bResult; } -bool RFbAL2230SelectChannel(unsigned long dwIoBase, unsigned char byChannel) +static bool RFbAL2230SelectChannel(unsigned long dwIoBase, unsigned char byChannel) { bool bResult; @@ -776,36 +776,6 @@ bool RFbInit( } /* - * Description: RF ShutDown function - * - * Parameters: - * In: - * byBBType - * byRFType - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ -bool RFbShutDown( - PSDevice pDevice -) -{ - bool bResult = true; - - switch (pDevice->byRFType) { - case RF_AIROHA7230: - bResult = IFRFbWriteEmbedded(pDevice->PortOffset, 0x1ABAEF00 + (BY_AL7230_REG_LEN << 3) + IFREGCTL_REGW); - break; - default: - bResult = true; - break; - } - return bResult; -} - -/* * Description: Select channel * * Parameters: diff --git a/drivers/staging/vt6655/vntwifi.c b/drivers/staging/vt6655/vntwifi.c index d8f4f8e7d05e..d2bdb71fe62d 100644 --- a/drivers/staging/vt6655/vntwifi.c +++ b/drivers/staging/vt6655/vntwifi.c @@ -752,25 +752,3 @@ VNTWIFIbChannelSwitch( //spin_unlock_irq(&pDevice->lock); return true; } - -/* - bool - VNTWIFIbRadarPresent( - void *pMgmtObject, - unsigned char byChannel -) { - PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject; - if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && - (byChannel == (unsigned char) pMgmt->uCurrChannel) && - (pMgmt->bSwitchChannel != true) && - (pMgmt->b11hEnable == true)) { - if (!compare_ether_addr(pMgmt->abyIBSSDFSOwner, CARDpGetCurrentAddress(pMgmt->pAdapter))) { - pMgmt->byNewChannel = CARDbyAutoChannelSelect(pMgmt->pAdapter,(unsigned char) pMgmt->uCurrChannel); - pMgmt->bSwitchChannel = true; - } - BEACONbSendBeacon(pMgmt); - CARDbChannelSwitch(pMgmt->pAdapter, 0, pMgmt->byNewChannel, 10); - } - return true; - } -*/ diff --git a/drivers/staging/vt6655/wcmd.c b/drivers/staging/vt6655/wcmd.c index d551653537b4..9c57eefe78fb 100644 --- a/drivers/staging/vt6655/wcmd.c +++ b/drivers/staging/vt6655/wcmd.c @@ -233,7 +233,7 @@ s_vProbeChannel( * * * Return Value: - * A ptr to Tx frame or NULL on allocation failue + * A ptr to Tx frame or NULL on allocation failure * -*/ diff --git a/drivers/staging/vt6655/wctl.c b/drivers/staging/vt6655/wctl.c index 9eb81b4eee80..f05f9f55398b 100644 --- a/drivers/staging/vt6655/wctl.c +++ b/drivers/staging/vt6655/wctl.c @@ -75,8 +75,8 @@ bool WCTLbIsDuplicate(PSCache pCache, PS802_11Header pMACHeader) for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) { pCacheEntry = &(pCache->asCacheEntry[uIndex]); if ((pCacheEntry->wFmSequence == pMACHeader->wSeqCtl) && - (!compare_ether_addr(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]))) -) { + ether_addr_equal(pCacheEntry->abyAddr2, + pMACHeader->abyAddr2)) { /* Duplicate match */ return true; } @@ -111,8 +111,8 @@ unsigned int WCTLuSearchDFCB(PSDevice pDevice, PS802_11Header pMACHeader) for (ii = 0; ii < pDevice->cbDFCB; ii++) { if ((pDevice->sRxDFCB[ii].bInUse == true) && - (!compare_ether_addr(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0]))) -) { + ether_addr_equal(pDevice->sRxDFCB[ii].abyAddr2, + pMACHeader->abyAddr2)) { // return ii; } diff --git a/drivers/staging/vt6655/wmgr.c b/drivers/staging/vt6655/wmgr.c index 9938813f997a..ed4b32b6d9ce 100644 --- a/drivers/staging/vt6655/wmgr.c +++ b/drivers/staging/vt6655/wmgr.c @@ -1680,7 +1680,8 @@ s_vMgrRxDeauthentication( vMgrDecodeDeauthen(&sFrame); DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP deauthed me, reason=%d.\n", cpu_to_le16((*(sFrame.pwReason)))); // TODO: update BSS list for specific BSSID if pre-authentication case - if (!compare_ether_addr(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID)) { + if (ether_addr_equal(sFrame.pHdr->sA3.abyAddr3, + pMgmt->abyCurrBSSID)) { if (pMgmt->eCurrState >= WMAC_STATE_AUTHPENDING) { pMgmt->sNodeDBTable[0].bActive = false; pMgmt->eCurrMode = WMAC_MODE_STANDBY; diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c index e8d9ecd2913a..044368a46c53 100644 --- a/drivers/staging/vt6655/wpactl.c +++ b/drivers/staging/vt6655/wpactl.c @@ -394,7 +394,7 @@ int wpa_set_keys(PSDevice pDevice, void *ctx, bool fcpfkernel) } else { // Key Table Full - if (!compare_ether_addr(¶m->addr[0], pDevice->abyBSSID)) { + if (ether_addr_equal(param->addr, pDevice->abyBSSID)) { //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n")); //spin_unlock_irq(&pDevice->lock); return -EINVAL; diff --git a/drivers/staging/vt6655/wroute.c b/drivers/staging/vt6655/wroute.c index b61328fbee87..85302c5e2bac 100644 --- a/drivers/staging/vt6655/wroute.c +++ b/drivers/staging/vt6655/wroute.c @@ -179,7 +179,7 @@ bool ROUTEbRelay(PSDevice pDevice, unsigned char *pbySkbData, unsigned int uData pHeadTD = pHeadTD->next; } - pLastTD->pTDInfo->skb = 0; + pLastTD->pTDInfo->skb = NULL; pLastTD->pTDInfo->byFlags = 0; pDevice->apCurrTD[TYPE_AC0DMA] = pHeadTD; diff --git a/drivers/staging/vt6655/wroute.h b/drivers/staging/vt6655/wroute.h index 5ecc190ae775..3abc1d36f89d 100644 --- a/drivers/staging/vt6655/wroute.h +++ b/drivers/staging/vt6655/wroute.h @@ -41,4 +41,4 @@ bool ROUTEbRelay(PSDevice pDevice, unsigned char *pbySkbData, unsigned int uDataLen, unsigned int uNodeIndex); -#endif // __WROUTE_H__ +#endif /* __WROUTE_H__ */ diff --git a/drivers/staging/vt6656/bssdb.c b/drivers/staging/vt6656/bssdb.c index ee79bbdf1a06..dad3f8c78e21 100644 --- a/drivers/staging/vt6656/bssdb.c +++ b/drivers/staging/vt6656/bssdb.c @@ -57,6 +57,7 @@ #include "control.h" #include "rndis.h" #include "iowpa.h" +#include "power.h" static int msglevel =MSG_LEVEL_INFO; //static int msglevel =MSG_LEVEL_DEBUG; @@ -126,7 +127,7 @@ PKnownBSS BSSpSearchBSSList(struct vnt_private *pDevice, if ((pCurrBSS->bActive) && (pCurrBSS->bSelected == false)) { - if (!compare_ether_addr(pCurrBSS->abyBSSID, pbyBSSID)) { + if (ether_addr_equal(pCurrBSS->abyBSSID, pbyBSSID)) { if (pSSID != NULL) { // compare ssid if ( !memcmp(pSSID->abySSID, @@ -242,8 +243,8 @@ void BSSvClearBSSList(struct vnt_private *pDevice, int bKeepCurrBSSID) for (ii = 0; ii < MAX_BSS_NUM; ii++) { if (bKeepCurrBSSID) { if (pMgmt->sBSSList[ii].bActive && - !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, - pMgmt->abyCurrBSSID)) { + ether_addr_equal(pMgmt->sBSSList[ii].abyBSSID, + pMgmt->abyCurrBSSID)) { //mike mark: there are two BSSID's in list. If that AP is in hidden ssid mode, one SSID is null, // but other's might not be obvious, so if it associate's with your STA, // you must keep the two of them!! @@ -277,7 +278,7 @@ PKnownBSS BSSpAddrIsInBSSList(struct vnt_private *pDevice, for (ii = 0; ii < MAX_BSS_NUM; ii++) { pBSSList = &(pMgmt->sBSSList[ii]); if (pBSSList->bActive) { - if (!compare_ether_addr(pBSSList->abyBSSID, abyBSSID)) { + if (ether_addr_equal(pBSSList->abyBSSID, abyBSSID)) { if (pSSID->len == ((PWLAN_IE_SSID)pBSSList->abySSID)->len){ if (memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pBSSList->abySSID)->abySSID, @@ -623,8 +624,8 @@ int BSSbIsSTAInNodeDB(struct vnt_private *pDevice, // Index = 0 reserved for AP Node for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) { if (pMgmt->sNodeDBTable[ii].bActive) { - if (!compare_ether_addr(abyDstAddr, - pMgmt->sNodeDBTable[ii].abyMACAddr)) { + if (ether_addr_equal(abyDstAddr, + pMgmt->sNodeDBTable[ii].abyMACAddr)) { *puNodeIndex = ii; return true; } @@ -813,8 +814,10 @@ void BSSvAddMulticastNode(struct vnt_private *pDevice) * -*/ -void BSSvSecondCallBack(struct vnt_private *pDevice) +void BSSvSecondCallBack(struct work_struct *work) { + struct vnt_private *pDevice = container_of(work, + struct vnt_private, second_callback_work.work); struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; int ii; PWLAN_IE_SSID pItemSSID, pCurrSSID; @@ -822,6 +825,9 @@ void BSSvSecondCallBack(struct vnt_private *pDevice) u32 uNonShortSlotSTACnt = 0; u32 uLongPreambleSTACnt = 0; + if (pDevice->Flags & fMP_DISCONNECTED) + return; + spin_lock_irq(&pDevice->lock); pDevice->uAssocCount = 0; @@ -1119,15 +1125,26 @@ else { } } - if (pDevice->bLinkPass == true) { - if (netif_queue_stopped(pDevice->dev)) - netif_wake_queue(pDevice->dev); - } + if (pDevice->bLinkPass == true) { + if (pMgmt->eAuthenMode < WMAC_AUTH_WPA || + pDevice->fWPA_Authened == true) { + if (++pDevice->tx_data_time_out > 40) { + pDevice->tx_trigger = true; + + PSbSendNullPacket(pDevice); + + pDevice->tx_trigger = false; + pDevice->tx_data_time_out = 0; + } + } + + if (netif_queue_stopped(pDevice->dev)) + netif_wake_queue(pDevice->dev); + } spin_unlock_irq(&pDevice->lock); - pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ); - add_timer(&pMgmt->sTimerSecondCallback); + schedule_delayed_work(&pDevice->second_callback_work, HZ); } /*+ diff --git a/drivers/staging/vt6656/bssdb.h b/drivers/staging/vt6656/bssdb.h index bce3b4654165..fc418555bc4d 100644 --- a/drivers/staging/vt6656/bssdb.h +++ b/drivers/staging/vt6656/bssdb.h @@ -262,7 +262,7 @@ void BSSvCreateOneNode(struct vnt_private *, u32 *puNodeIndex); void BSSvUpdateAPNode(struct vnt_private *, u16 *pwCapInfo, PWLAN_IE_SUPP_RATES pItemRates, PWLAN_IE_SUPP_RATES pExtSuppRates); -void BSSvSecondCallBack(struct vnt_private *); +void BSSvSecondCallBack(struct work_struct *work); void BSSvUpdateNodeTxCounter(struct vnt_private *, PSStatCounter pStatistic, u8 byTSR, u8 byPktNO); diff --git a/drivers/staging/vt6656/channel.c b/drivers/staging/vt6656/channel.c index 5158ff4b346a..e430b35463b6 100644 --- a/drivers/staging/vt6656/channel.c +++ b/drivers/staging/vt6656/channel.c @@ -403,7 +403,7 @@ exit: void CHvInitChannelTable(struct vnt_private *pDevice) { - int bMultiBand = false; + bool bMultiBand = false; int ii; for (ii = 1; ii <= CB_MAX_CHANNEL; ii++) diff --git a/drivers/staging/vt6656/desc.h b/drivers/staging/vt6656/desc.h index 4675135aa258..afe7074c3037 100644 --- a/drivers/staging/vt6656/desc.h +++ b/drivers/staging/vt6656/desc.h @@ -146,15 +146,6 @@ /* * TX FIFO header */ -typedef struct tagSTxBufHead { - u32 adwTxKey[4]; - u16 wFIFOCtl; - u16 wTimeStamp; - u16 wFragCtl; - u16 wReserved; -} __attribute__ ((__packed__)) -STxBufHead, *PSTxBufHead; -typedef const STxBufHead *PCSTxBufHead; typedef struct tagSTxShortBufHead { u16 wFIFOCtl; diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h index 8e396341c5e8..62b7de19b371 100644 --- a/drivers/staging/vt6656/device.h +++ b/drivers/staging/vt6656/device.h @@ -384,8 +384,8 @@ struct vnt_private { struct tasklet_struct CmdWorkItem; struct tasklet_struct EventWorkItem; - struct tasklet_struct ReadWorkItem; - struct tasklet_struct RxMngWorkItem; + struct work_struct read_work_item; + struct work_struct rx_mng_work_item; u32 rx_buf_sz; int multicast_limit; @@ -579,6 +579,9 @@ struct vnt_private { u8 abyOFDMAPwrTbl[42]; u16 wCurrentRate; + u16 tx_rate_fb0; + u16 tx_rate_fb1; + u16 wRTSThreshold; u16 wFragmentationThreshold; u8 byShortRetryLimit; @@ -707,13 +710,12 @@ struct vnt_private { u8 byBBCR09; /* command timer */ - struct timer_list sTimerCommand; - - struct timer_list sTimerTxData; - unsigned long nTxDataTimeCout; - int fTxDataInSleep; - int IsTxDataTrigger; + struct delayed_work run_command_work; + /* One second callback */ + struct delayed_work second_callback_work; + u8 tx_data_time_out; + bool tx_trigger; int fWPA_Authened; /*is WPA/WPA-PSK or WPA2/WPA2-PSK authen?? */ u8 byReAssocCount; u8 byLinkWaitCount; diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c index ea7d443b11d0..75dc92d64056 100644 --- a/drivers/staging/vt6656/dpc.c +++ b/drivers/staging/vt6656/dpc.c @@ -136,9 +136,9 @@ static void s_vProcessRxMACHeader(struct vnt_private *pDevice, }; pbyRxBuffer = (u8 *) (pbyRxBufferAddr + cbHeaderSize); - if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) { + if (ether_addr_equal(pbyRxBuffer, pDevice->abySNAP_Bridgetunnel)) { cbHeaderSize += 6; - } else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) { + } else if (ether_addr_equal(pbyRxBuffer, pDevice->abySNAP_RFC1042)) { cbHeaderSize += 6; pwType = (u16 *) (pbyRxBufferAddr + cbHeaderSize); if ((*pwType == cpu_to_be16(ETH_P_IPX)) || @@ -361,7 +361,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, struct vnt_rcb *pRCB, if ((pMgmt->eCurrMode == WMAC_MODE_STANDBY) || (pMgmt->eCurrMode == WMAC_MODE_ESS_STA)) { if (pMgmt->sNodeDBTable[0].bActive) { - if (!compare_ether_addr(pMgmt->abyCurrBSSID, pMACHeader->addr2)) { + if (ether_addr_equal(pMgmt->abyCurrBSSID, pMACHeader->addr2)) { if (pMgmt->sNodeDBTable[0].uInActiveCount != 0) pMgmt->sNodeDBTable[0].uInActiveCount = 0; } @@ -374,8 +374,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, struct vnt_rcb *pRCB, return false; } - if (compare_ether_addr(pDevice->abyCurrentNetAddr, - pMACHeader->addr1)) { + if (!ether_addr_equal(pDevice->abyCurrentNetAddr, pMACHeader->addr1)) { return false; } } @@ -383,8 +382,8 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, struct vnt_rcb *pRCB, // Use for TKIP MIC s_vGetDASA(pbyFrame, &cbHeaderSize, &pDevice->sRxEthHeader); - if (!compare_ether_addr((u8 *)&(pDevice->sRxEthHeader.h_source[0]), - pDevice->abyCurrentNetAddr)) + if (ether_addr_equal((u8 *)pDevice->sRxEthHeader.h_source, + pDevice->abyCurrentNetAddr)) return false; if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) { @@ -560,7 +559,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, struct vnt_rcb *pRCB, } if (pDevice->bIsRxMngWorkItemQueued == false) { pDevice->bIsRxMngWorkItemQueued = true; - tasklet_schedule(&pDevice->RxMngWorkItem); + schedule_work(&pDevice->rx_mng_work_item); } } @@ -1333,11 +1332,16 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb, return true; } -void RXvWorkItem(struct vnt_private *pDevice) +void RXvWorkItem(struct work_struct *work) { + struct vnt_private *pDevice = + container_of(work, struct vnt_private, read_work_item); int ntStatus; struct vnt_rcb *pRCB = NULL; + if (pDevice->Flags & fMP_DISCONNECTED) + return; + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Polling Thread\n"); spin_lock_irq(&pDevice->lock); @@ -1384,17 +1388,22 @@ void RXvFreeRCB(struct vnt_rcb *pRCB, int bReAllocSkb) (pDevice->bIsRxWorkItemQueued == false) ) { pDevice->bIsRxWorkItemQueued = true; - tasklet_schedule(&pDevice->ReadWorkItem); + schedule_work(&pDevice->read_work_item); } DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----RXFreeRCB %d %d\n",pDevice->NumRecvFreeList, pDevice->NumRecvMngList); } -void RXvMngWorkItem(struct vnt_private *pDevice) +void RXvMngWorkItem(struct work_struct *work) { + struct vnt_private *pDevice = + container_of(work, struct vnt_private, rx_mng_work_item); struct vnt_rcb *pRCB = NULL; struct vnt_rx_mgmt *pRxPacket; int bReAllocSkb = false; + if (pDevice->Flags & fMP_DISCONNECTED) + return; + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Mng Thread\n"); spin_lock_irq(&pDevice->lock); diff --git a/drivers/staging/vt6656/dpc.h b/drivers/staging/vt6656/dpc.h index 95388dc03ee3..8d524345dfdb 100644 --- a/drivers/staging/vt6656/dpc.h +++ b/drivers/staging/vt6656/dpc.h @@ -32,9 +32,9 @@ #include "device.h" #include "wcmd.h" -void RXvWorkItem(void *Context); +void RXvWorkItem(struct work_struct *work); -void RXvMngWorkItem(void *Context); +void RXvMngWorkItem(struct work_struct *work); void RXvFreeRCB(struct vnt_rcb *pRCB, int bReAllocSkb); diff --git a/drivers/staging/vt6656/firmware.c b/drivers/staging/vt6656/firmware.c index a1dc3a4cfd9c..cd2ea76c8b1e 100644 --- a/drivers/staging/vt6656/firmware.c +++ b/drivers/staging/vt6656/firmware.c @@ -35,8 +35,8 @@ #include "control.h" #include "rndis.h" -static int msglevel =MSG_LEVEL_INFO; -//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel = MSG_LEVEL_INFO; +/* static int msglevel = MSG_LEVEL_DEBUG; */ #define FIRMWARE_VERSION 0x133 /* version 1.51 */ #define FIRMWARE_NAME "vntwusb.fw" @@ -72,18 +72,17 @@ int FIRMWAREbDownload(struct vnt_private *pDevice) memcpy(pBuffer, fw->data + ii, wLength); NdisStatus = CONTROLnsRequestOutAsyn(pDevice, - 0, - 0x1200+ii, - 0x0000, - wLength, - pBuffer - ); + 0, + 0x1200+ii, + 0x0000, + wLength, + pBuffer); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Download firmware...%d %zu\n", ii, fw->size); if (NdisStatus != STATUS_SUCCESS) goto free_fw; - } + } result = true; free_fw: @@ -101,48 +100,47 @@ int FIRMWAREbBrach2Sram(struct vnt_private *pDevice) { int NdisStatus; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Branch to Sram\n"); - - NdisStatus = CONTROLnsRequestOut(pDevice, - 1, - 0x1200, - 0x0000, - 0, - NULL - ); - - if (NdisStatus != STATUS_SUCCESS) { - return (false); - } else { - return (true); - } + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Branch to Sram\n"); + + NdisStatus = CONTROLnsRequestOut(pDevice, + 1, + 0x1200, + 0x0000, + 0, + NULL); + if (NdisStatus != STATUS_SUCCESS) + return false; + else + return true; } int FIRMWAREbCheckVersion(struct vnt_private *pDevice) { int ntStatus; - ntStatus = CONTROLnsRequestIn(pDevice, - MESSAGE_TYPE_READ, - 0, - MESSAGE_REQUEST_VERSION, - 2, - (u8 *) &(pDevice->wFirmwareVersion)); - - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Firmware Version [%04x]\n", pDevice->wFirmwareVersion); - if (ntStatus != STATUS_SUCCESS) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Firmware Invalid.\n"); - return false; - } - if (pDevice->wFirmwareVersion == 0xFFFF) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"In Loader.\n"); - return false; - } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Firmware Version [%04x]\n", pDevice->wFirmwareVersion); - if (pDevice->wFirmwareVersion < FIRMWARE_VERSION) { - // branch to loader for download new firmware - FIRMWAREbBrach2Sram(pDevice); - return false; - } - return true; + ntStatus = CONTROLnsRequestIn(pDevice, + MESSAGE_TYPE_READ, + 0, + MESSAGE_REQUEST_VERSION, + 2, + (u8 *) &(pDevice->wFirmwareVersion)); + + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Firmware Version [%04x]\n", + pDevice->wFirmwareVersion); + if (ntStatus != STATUS_SUCCESS) { + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Firmware Invalid.\n"); + return false; + } + if (pDevice->wFirmwareVersion == 0xFFFF) { + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"In Loader.\n"); + return false; + } + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Firmware Version [%04x]\n", + pDevice->wFirmwareVersion); + if (pDevice->wFirmwareVersion < FIRMWARE_VERSION) { + /* branch to loader for download new firmware */ + FIRMWAREbBrach2Sram(pDevice); + return false; + } + return true; } diff --git a/drivers/staging/vt6656/hostap.c b/drivers/staging/vt6656/hostap.c index c699a3058b39..7d96fe7a3e41 100644 --- a/drivers/staging/vt6656/hostap.c +++ b/drivers/staging/vt6656/hostap.c @@ -414,7 +414,7 @@ static int hostap_set_encryption(struct vnt_private *pDevice, int ret = 0; s32 iNodeIndex = -1; int ii; - int bKeyTableFull = false; + bool bKeyTableFull = false; u16 wKeyCtl = 0; param->u.crypt.err = 0; diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c index 8872e0f84f40..63917abbbd00 100644 --- a/drivers/staging/vt6656/iwctl.c +++ b/drivers/staging/vt6656/iwctl.c @@ -60,7 +60,7 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev) pDevice->wstats.status = pDevice->eOPMode; if (pDevice->scStatistic.LinkQuality > 100) pDevice->scStatistic.LinkQuality = 100; - pDevice->wstats.qual.qual =(u8)pDevice->scStatistic.LinkQuality; + pDevice->wstats.qual.qual = (u8)pDevice->scStatistic.LinkQuality; RFvRSSITodBm(pDevice, (u8)(pDevice->uCurrRSSI), &ldBm); pDevice->wstats.qual.level = ldBm; pDevice->wstats.qual.noise = 0; @@ -190,7 +190,7 @@ int iwctl_giwscan(struct net_device *dev, struct iw_request_info *info, return -EAGAIN; } pBSS = &(pMgmt->sBSSList[0]); - for (ii = 0, jj = 0; jj < MAX_BSS_NUM ; jj++) { + for (ii = 0, jj = 0; jj < MAX_BSS_NUM; jj++) { if (current_ev >= end_buf) break; pBSS = &(pMgmt->sBSSList[jj]); @@ -225,7 +225,7 @@ int iwctl_giwscan(struct net_device *dev, struct iw_request_info *info, iwe.u.freq.m = pBSS->uChannel; iwe.u.freq.e = 0; iwe.u.freq.i = 0; - current_ev = iwe_stream_add_event(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); { int f = (int)pBSS->uChannel - 1; if (f < 0) @@ -400,7 +400,7 @@ int iwctl_siwmode(struct net_device *dev, struct iw_request_info *info, if (pDevice->flags & DEVICE_FLAGS_OPENED) pDevice->bCommit = true; } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to ad-hoc \n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to ad-hoc\n"); break; case IW_MODE_AUTO: case IW_MODE_INFRA: @@ -409,7 +409,7 @@ int iwctl_siwmode(struct net_device *dev, struct iw_request_info *info, if (pDevice->flags & DEVICE_FLAGS_OPENED) pDevice->bCommit = true; } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to infrastructure \n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to infrastructure\n"); break; case IW_MODE_MASTER: @@ -422,7 +422,7 @@ int iwctl_siwmode(struct net_device *dev, struct iw_request_info *info, if (pDevice->flags & DEVICE_FLAGS_OPENED) pDevice->bCommit = true; } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to Access Point \n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to Access Point\n"); break; case IW_MODE_REPEAT: @@ -657,8 +657,8 @@ int iwctl_siwap(struct net_device *dev, struct iw_request_info *info, unsigned uSameBssidNum = 0; for (ii = 0; ii < MAX_BSS_NUM; ii++) { if (pMgmt->sBSSList[ii].bActive && - !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, - pMgmt->abyDesireBSSID)) { + ether_addr_equal(pMgmt->sBSSList[ii].abyBSSID, + pMgmt->abyDesireBSSID)) { uSameBssidNum++; } } @@ -786,8 +786,8 @@ int iwctl_siwessid(struct net_device *dev, struct iw_request_info *info, if (wrq->flags == 0) { // Just send an empty SSID list memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); - memset(pMgmt->abyDesireBSSID, 0xFF,6); - PRINT_K("set essid to 'any' \n"); + memset(pMgmt->abyDesireBSSID, 0xFF, 6); + PRINT_K("set essid to 'any'\n"); // Unknown desired AP, so here need not associate?? return 0; } else { @@ -798,15 +798,15 @@ int iwctl_siwessid(struct net_device *dev, struct iw_request_info *info, memcpy(pItemSSID->abySSID, extra, wrq->length); if (pItemSSID->abySSID[wrq->length] == '\0') { - if (wrq->length>0) + if (wrq->length > 0) pItemSSID->len = wrq->length; } else { pItemSSID->len = wrq->length; } - PRINT_K("set essid to %s \n", pItemSSID->abySSID); + PRINT_K("set essid to %s\n", pItemSSID->abySSID); // mike: need clear desiredBSSID - if (pItemSSID->len==0) { + if (pItemSSID->len == 0) { memset(pMgmt->abyDesireBSSID, 0xFF, 6); return 0; } @@ -840,8 +840,8 @@ int iwctl_siwessid(struct net_device *dev, struct iw_request_info *info, // are two same BSSID exist in list ? for (ii = 0; ii < MAX_BSS_NUM; ii++) { if (pMgmt->sBSSList[ii].bActive && - !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, - pCurr->abyBSSID)) { + ether_addr_equal(pMgmt->sBSSList[ii].abyBSSID, + pCurr->abyBSSID)) { uSameBssidNum++; } } @@ -860,7 +860,7 @@ int iwctl_siwessid(struct net_device *dev, struct iw_request_info *info, return 0; } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set essid = %s \n", pItemSSID->abySSID); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set essid = %s\n", pItemSSID->abySSID); } if (pDevice->flags & DEVICE_FLAGS_OPENED) @@ -893,7 +893,7 @@ int iwctl_giwessid(struct net_device *dev, struct iw_request_info *info, memcpy(extra, pItemSSID->abySSID, pItemSSID->len); extra[pItemSSID->len] = '\0'; - wrq->length = pItemSSID->len; + wrq->length = pItemSSID->len; wrq->flags = 1; // active return 0; @@ -915,7 +915,7 @@ int iwctl_siwrate(struct net_device *dev, struct iw_request_info *info, 0x60, 0x6C, 0x90 }; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRATE \n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRATE\n"); if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) { rc = -EINVAL; return rc; @@ -953,7 +953,7 @@ int iwctl_siwrate(struct net_device *dev, struct iw_request_info *info, } // Check that it is valid // brate is index of abySupportedRates[] - if (brate > 13 ) { + if (brate > 13) { rc = -EINVAL; return rc; } @@ -967,7 +967,7 @@ int iwctl_siwrate(struct net_device *dev, struct iw_request_info *info, pDevice->uConnectionRate = 3; } else { pDevice->uConnectionRate = brate; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Fixed to Rate %d \n", pDevice->uConnectionRate); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Fixed to Rate %d\n", pDevice->uConnectionRate); } } else { pDevice->bFixRate = false; @@ -1017,7 +1017,7 @@ int iwctl_giwrate(struct net_device *dev, struct iw_request_info *info, if (pDevice->byBBType == BB_TYPE_11A) brate = 0x6C; } - if (pDevice->uConnectionRate == 13) + if (pDevice->uConnectionRate == 13) brate = abySupportedRates[pDevice->wCurrentRate]; wrq->value = brate * 500000; // If more than one rate, set auto @@ -1286,7 +1286,7 @@ int iwctl_giwencode(struct net_device *dev, struct iw_request_info *info, if (index < 1) { // get default key if (pDevice->byKeyIndex < WLAN_WEP_NKEYS) index = pDevice->byKeyIndex; - else + else index = 0; } else { index--; @@ -1366,14 +1366,14 @@ int iwctl_siwpower(struct net_device *dev, struct iw_request_info *info, switch (wrq->flags & IW_POWER_MODE) { case IW_POWER_UNICAST_R: - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R \n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R\n"); rc = -EINVAL; break; case IW_POWER_ALL_R: - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ALL_R \n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ALL_R\n"); rc = -EINVAL; case IW_POWER_ON: - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ON \n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ON\n"); break; default: rc = -EINVAL; @@ -1465,7 +1465,7 @@ int iwctl_siwauth(struct net_device *dev, struct iw_request_info *info, case IW_AUTH_CIPHER_PAIRWISE: pairwise = wrq->value; PRINT_K("iwctl_siwauth:set pairwise=%d\n", pairwise); - if (pairwise == IW_AUTH_CIPHER_CCMP){ + if (pairwise == IW_AUTH_CIPHER_CCMP) { pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; } else if (pairwise == IW_AUTH_CIPHER_TKIP) { pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; @@ -1490,13 +1490,13 @@ int iwctl_siwauth(struct net_device *dev, struct iw_request_info *info, } break; case IW_AUTH_KEY_MGMT: - PRINT_K("iwctl_siwauth(wpa_version=%d):set KEY_MGMT=%d\n", wpa_version,wrq->value); - if (wpa_version == IW_AUTH_WPA_VERSION_WPA2){ + PRINT_K("iwctl_siwauth(wpa_version=%d):set KEY_MGMT=%d\n", wpa_version, wrq->value); + if (wpa_version == IW_AUTH_WPA_VERSION_WPA2) { if (wrq->value == IW_AUTH_KEY_MGMT_PSK) pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK; else pMgmt->eAuthenMode = WMAC_AUTH_WPA2; } else if (wpa_version == IW_AUTH_WPA_VERSION_WPA) { - if (wrq->value == 0){ + if (wrq->value == 0) { pMgmt->eAuthenMode = WMAC_AUTH_WPANONE; } else if (wrq->value == IW_AUTH_KEY_MGMT_PSK) pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK; @@ -1558,17 +1558,17 @@ int iwctl_siwgenie(struct net_device *dev, struct iw_request_info *info, if (pMgmt == NULL) return -EFAULT; - if (wrq->length){ + if (wrq->length) { if ((wrq->length < 2) || (extra[1] + 2 != wrq->length)) { ret = -EINVAL; goto out; } - if (wrq->length > MAX_WPA_IE_LEN){ + if (wrq->length > MAX_WPA_IE_LEN) { ret = -ENOMEM; goto out; } memset(pMgmt->abyWPAIE, 0, MAX_WPA_IE_LEN); - if (copy_from_user(pMgmt->abyWPAIE, extra, wrq->length)){ + if (copy_from_user(pMgmt->abyWPAIE, extra, wrq->length)) { ret = -EFAULT; goto out; } @@ -1615,7 +1615,7 @@ int iwctl_siwencodeext(struct net_device *dev, struct iw_request_info *info, struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; struct iw_point *wrq = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext*)extra; - struct viawget_wpa_param *param=NULL; + struct viawget_wpa_param *param = NULL; // original member wpa_alg alg_name; u8 addr[6]; @@ -1658,8 +1658,8 @@ int iwctl_siwencodeext(struct net_device *dev, struct iw_request_info *info, alg_name = WPA_ALG_CCMP; break; default: - PRINT_K("Unknown alg = %d\n",ext->alg); - ret= -ENOMEM; + PRINT_K("Unknown alg = %d\n", ext->alg); + ret = -ENOMEM; goto error; } // recover addr @@ -1671,7 +1671,7 @@ int iwctl_siwencodeext(struct net_device *dev, struct iw_request_info *info, set_tx = 1; // recover seq,seq_len if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { - seq_len=IW_ENCODE_SEQ_MAX_SIZE; + seq_len = IW_ENCODE_SEQ_MAX_SIZE; memcpy(seq, ext->rx_seq, seq_len); } // recover key,key_len @@ -1702,7 +1702,7 @@ int iwctl_siwencodeext(struct net_device *dev, struct iw_request_info *info, /****set if current action is Network Manager count?? */ /****this method is so foolish,but there is no other way??? */ if (param->u.wpa_key.alg_name == WPA_ALG_NONE) { - if (param->u.wpa_key.key_index ==0) { + if (param->u.wpa_key.key_index == 0) { pDevice->bwextstep0 = true; } if ((pDevice->bwextstep0 == true) && (param->u.wpa_key.key_index == 1)) { @@ -1761,7 +1761,7 @@ int iwctl_siwmlme(struct net_device *dev, struct iw_request_info *info, ret = -EINVAL; return ret; } - switch (mlme->cmd){ + switch (mlme->cmd) { case IW_MLME_DEAUTH: case IW_MLME_DISASSOC: if (pDevice->bLinkPass == true) { @@ -1815,7 +1815,6 @@ static const iw_handler iwctl_handler[] = { IW_HANDLER(SIOCGIWPOWER, iwctl_giwpower), IW_HANDLER(SIOCSIWGENIE, iwctl_siwgenie), IW_HANDLER(SIOCGIWGENIE, iwctl_giwgenie), - IW_HANDLER(SIOCSIWMLME, iwctl_siwmlme), IW_HANDLER(SIOCSIWAUTH, iwctl_siwauth), IW_HANDLER(SIOCGIWAUTH, iwctl_giwauth), IW_HANDLER(SIOCSIWENCODEEXT, iwctl_siwencodeext), diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c index 205590b0e9c8..be92c048a12e 100644 --- a/drivers/staging/vt6656/key.c +++ b/drivers/staging/vt6656/key.c @@ -151,7 +151,7 @@ int KeybGetKey(PSKeyManagement pTable, u8 *pbyBSSID, u32 dwKeyIndex, *pKey = NULL; for (i=0;i<MAX_KEY_TABLE;i++) { if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { if (dwKeyIndex == 0xFFFFFFFF) { if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) { *pKey = &(pTable->KeyTable[i].PairwiseKey); @@ -213,7 +213,7 @@ int KeybSetKey(struct vnt_private *pDevice, PSKeyManagement pTable, j = i; } if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { // found table already exist if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key @@ -395,7 +395,7 @@ int KeybRemoveKey(struct vnt_private *pDevice, PSKeyManagement pTable, } else { for (i=0;i<MAX_KEY_TABLE;i++) { if ( (pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { if ((dwKeyIndex & PAIRWISE_KEY) != 0) { pTable->KeyTable[i].PairwiseKey.bKeyValid = false; @@ -445,7 +445,7 @@ int KeybRemoveAllKey(struct vnt_private *pDevice, PSKeyManagement pTable, for (i=0;i<MAX_KEY_TABLE;i++) { if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { pTable->KeyTable[i].PairwiseKey.bKeyValid = false; for (u = 0; u < MAX_GROUP_KEY; u++) pTable->KeyTable[i].GroupKey[u].bKeyValid = false; @@ -480,7 +480,7 @@ int KeybGetTransmitKey(PSKeyManagement pTable, u8 *pbyBSSID, u32 dwKeyType, for (i = 0; i < MAX_KEY_TABLE; i++) { if ((pTable->KeyTable[i].bInUse == true) && - !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { + ether_addr_equal(pTable->KeyTable[i].abyBSSID, pbyBSSID)) { if (dwKeyType == PAIRWISE_KEY) { diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 6f9d28182445..5e4a5d0988d7 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -702,6 +702,16 @@ vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id) device_set_options(pDevice); spin_lock_init(&pDevice->lock); + INIT_DELAYED_WORK(&pDevice->run_command_work, vRunCommand); + INIT_DELAYED_WORK(&pDevice->second_callback_work, BSSvSecondCallBack); + INIT_WORK(&pDevice->read_work_item, RXvWorkItem); + INIT_WORK(&pDevice->rx_mng_work_item, RXvMngWorkItem); + + pDevice->pControlURB = usb_alloc_urb(0, GFP_ATOMIC); + if (!pDevice->pControlURB) { + DBG_PRT(MSG_LEVEL_ERR, KERN_ERR"Failed to alloc control urb\n"); + goto err_netdev; + } pDevice->tx_80211 = device_dma0_tx_80211; pDevice->vnt_mgmt.pAdapter = (void *) pDevice; @@ -849,23 +859,15 @@ static bool device_alloc_bufs(struct vnt_private *pDevice) pRCB++; } - pDevice->pControlURB = usb_alloc_urb(0, GFP_ATOMIC); - if (pDevice->pControlURB == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR"Failed to alloc control urb\n"); - goto free_rx_tx; - } - pDevice->pInterruptURB = usb_alloc_urb(0, GFP_ATOMIC); if (pDevice->pInterruptURB == NULL) { DBG_PRT(MSG_LEVEL_ERR,KERN_ERR"Failed to alloc int urb\n"); - usb_free_urb(pDevice->pControlURB); goto free_rx_tx; } pDevice->intBuf.pDataBuf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL); if (pDevice->intBuf.pDataBuf == NULL) { DBG_PRT(MSG_LEVEL_ERR,KERN_ERR"Failed to alloc int buf\n"); - usb_free_urb(pDevice->pControlURB); usb_free_urb(pDevice->pInterruptURB); goto free_rx_tx; } @@ -981,10 +983,11 @@ static int device_open(struct net_device *dev) } vMgrObjectInit(pDevice); - tasklet_init(&pDevice->RxMngWorkItem, (void *)RXvMngWorkItem, (unsigned long)pDevice); - tasklet_init(&pDevice->ReadWorkItem, (void *)RXvWorkItem, (unsigned long)pDevice); + tasklet_init(&pDevice->EventWorkItem, (void *)INTvWorkItem, (unsigned long)pDevice); - add_timer(&pDevice->vnt_mgmt.sTimerSecondCallback); + + schedule_delayed_work(&pDevice->second_callback_work, HZ); + pDevice->int_interval = 100; /* max 100 microframes */ pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; @@ -1000,7 +1003,7 @@ static int device_open(struct net_device *dev) pDevice->bWPASuppWextEnabled = false; pDevice->byReAssocCount = 0; - RXvWorkItem(pDevice); + schedule_work(&pDevice->read_work_item); INTvWorkItem(pDevice); /* if WEP key already set by iwconfig but device not yet open */ @@ -1035,9 +1038,7 @@ free_rx_tx: device_free_rx_bufs(pDevice); device_free_tx_bufs(pDevice); device_free_int_bufs(pDevice); - usb_kill_urb(pDevice->pControlURB); usb_kill_urb(pDevice->pInterruptURB); - usb_free_urb(pDevice->pControlURB); usb_free_urb(pDevice->pInterruptURB); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_open fail.. \n"); @@ -1076,18 +1077,19 @@ static int device_close(struct net_device *dev) MP_CLEAR_FLAG(pDevice, fMP_POST_WRITES); MP_CLEAR_FLAG(pDevice, fMP_POST_READS); pDevice->fKillEventPollingThread = true; - del_timer(&pDevice->sTimerCommand); - del_timer(&pMgmt->sTimerSecondCallback); - del_timer(&pDevice->sTimerTxData); + cancel_delayed_work_sync(&pDevice->run_command_work); + cancel_delayed_work_sync(&pDevice->second_callback_work); if (pDevice->bDiversityRegCtlON) { del_timer(&pDevice->TimerSQ3Tmax1); del_timer(&pDevice->TimerSQ3Tmax2); del_timer(&pDevice->TimerSQ3Tmax3); } - tasklet_kill(&pDevice->RxMngWorkItem); - tasklet_kill(&pDevice->ReadWorkItem); + + cancel_work_sync(&pDevice->rx_mng_work_item); + cancel_work_sync(&pDevice->read_work_item); + tasklet_kill(&pDevice->EventWorkItem); pDevice->bRoaming = false; @@ -1105,9 +1107,7 @@ static int device_close(struct net_device *dev) device_free_int_bufs(pDevice); device_free_frag_bufs(pDevice); - usb_kill_urb(pDevice->pControlURB); usb_kill_urb(pDevice->pInterruptURB); - usb_free_urb(pDevice->pControlURB); usb_free_urb(pDevice->pInterruptURB); BSSvClearNodeDBTable(pDevice, 0); @@ -1131,9 +1131,12 @@ static void vt6656_disconnect(struct usb_interface *intf) if (device->dev) { unregister_netdev(device->dev); + + usb_kill_urb(device->pControlURB); + usb_free_urb(device->pControlURB); + free_netdev(device->dev); } - } static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev) diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c index edc8975b2e2a..6334315807bb 100644 --- a/drivers/staging/vt6656/power.c +++ b/drivers/staging/vt6656/power.c @@ -257,10 +257,8 @@ int PSbSendNullPacket(struct vnt_private *pDevice) if (pDevice->bLinkPass == false) return false; - if ((pDevice->bEnablePSMode == false) && - (pDevice->fTxDataInSleep == false)) { - return false; - } + if (pDevice->bEnablePSMode == false && pDevice->tx_trigger == false) + return false; memset(pMgmt->pbyPSPacketPool, 0, sizeof(struct vnt_tx_mgmt) + WLAN_NULLDATA_FR_MAXLEN); diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 14f3e852215d..35a3ddb41a6a 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -98,21 +98,18 @@ static void s_vSaveTxPktInfo(struct vnt_private *pDevice, u8 byPktNum, static void *s_vGetFreeContext(struct vnt_private *pDevice); -static void s_vGenerateTxParameter(struct vnt_private *pDevice, - u8 byPktType, u16 wCurrentRate, void *pTxBufHead, void *pvRrvTime, - void *rts_cts, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx, - struct ethhdr *psEthHeader, bool need_rts); - -static u32 s_uFillDataHead(struct vnt_private *pDevice, - u8 byPktType, u16 wCurrentRate, void *pTxDataHead, u32 cbFrameLength, - u32 uDMAIdx, int bNeedAck, u8 byFBOption); +static u16 s_vGenerateTxParameter(struct vnt_private *pDevice, + u8 byPktType, u16 wCurrentRate, struct vnt_tx_buffer *tx_buffer, + struct vnt_mic_hdr **mic_hdr, u32 need_mic, u32 cbFrameSize, + int bNeedACK, u32 uDMAIdx, struct ethhdr *psEthHeader, bool need_rts); static void s_vGenerateMACHeader(struct vnt_private *pDevice, u8 *pbyBufferAddr, u16 wDuration, struct ethhdr *psEthHeader, int bNeedEncrypt, u16 wFragType, u32 uDMAIdx, u32 uFragIdx); -static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf, - u8 *pbyIVHead, PSKeyItem pTransmitKey, u8 *pbyHdrBuf, u16 wPayloadLen, +static void s_vFillTxKey(struct vnt_private *pDevice, + struct vnt_tx_fifo_head *fifo_head, u8 *pbyIVHead, + PSKeyItem pTransmitKey, u8 *pbyHdrBuf, u16 wPayloadLen, struct vnt_mic_hdr *mic_hdr); static void s_vSWencryption(struct vnt_private *pDevice, @@ -124,11 +121,11 @@ static unsigned int s_uGetTxRsvTime(struct vnt_private *pDevice, u8 byPktType, static u16 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice, u8 byRTSRsvType, u8 byPktType, u32 cbFrameLength, u16 wCurrentRate); -static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, +static u16 s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, u8 byPktType, union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck, u16 wCurrentRate, u8 byFBOption); -static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType, +static u16 s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType, union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck, struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption); @@ -183,10 +180,12 @@ static void s_vSaveTxPktInfo(struct vnt_private *pDevice, u8 byPktNum, ETH_ALEN); } -static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf, - u8 *pbyIVHead, PSKeyItem pTransmitKey, u8 *pbyHdrBuf, - u16 wPayloadLen, struct vnt_mic_hdr *mic_hdr) +static void s_vFillTxKey(struct vnt_private *pDevice, + struct vnt_tx_fifo_head *fifo_head, u8 *pbyIVHead, + PSKeyItem pTransmitKey, u8 *pbyHdrBuf, u16 wPayloadLen, + struct vnt_mic_hdr *mic_hdr) { + u8 *pbyBuf = (u8 *)&fifo_head->adwTxKey[0]; u32 *pdwIV = (u32 *)pbyIVHead; u32 *pdwExtIV = (u32 *)((u8 *)pbyIVHead + 4); struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *)pbyHdrBuf; @@ -431,185 +430,114 @@ static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType, { u32 uCTSTime = 0, uDurTime = 0; - switch (byDurType) { + switch (byDurType) { + case RTSDUR_BB: + case RTSDUR_BA: + case RTSDUR_BA_F0: + case RTSDUR_BA_F1: + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, + 14, pDevice->byTopCCKBasicRate); + uDurTime = uCTSTime + 2 * pDevice->uSIFS + + s_uGetTxRsvTime(pDevice, byPktType, + cbFrameLength, wRate, bNeedAck); + break; - case RTSDUR_BB: //RTSDuration_bb - uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); - break; + case RTSDUR_AA: + case RTSDUR_AA_F0: + case RTSDUR_AA_F1: + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, + 14, pDevice->byTopOFDMBasicRate); + uDurTime = uCTSTime + 2 * pDevice->uSIFS + + s_uGetTxRsvTime(pDevice, byPktType, + cbFrameLength, wRate, bNeedAck); + break; - case RTSDUR_BA: //RTSDuration_ba - uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); - break; + case CTSDUR_BA: + case CTSDUR_BA_F0: + case CTSDUR_BA_F1: + uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, + byPktType, cbFrameLength, wRate, bNeedAck); + break; - case RTSDUR_AA: //RTSDuration_aa - uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); - break; + default: + break; + } - case CTSDUR_BA: //CTSDuration_ba - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); - break; + return cpu_to_le16((u16)uDurTime); +} - case RTSDUR_BA_F0: //RTSDuration_ba_f0 - uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck); - } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); - } - break; - - case RTSDUR_AA_F0: //RTSDuration_aa_f0 - uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck); - } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); - } - break; +static u16 vnt_rxtx_datahead_g(struct vnt_private *priv, u8 pkt_type, u16 rate, + struct vnt_tx_datahead_g *buf, u32 frame_len, int need_ack) +{ + /* Get SignalField,ServiceField,Length */ + BBvCalculateParameter(priv, frame_len, rate, pkt_type, &buf->a); + BBvCalculateParameter(priv, frame_len, priv->byTopCCKBasicRate, + PK_TYPE_11B, &buf->b); - case RTSDUR_BA_F1: //RTSDuration_ba_f1 - uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck); - } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck); - } - break; - - case RTSDUR_AA_F1: //RTSDuration_aa_f1 - uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck); - } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck); - } - break; + /* Get Duration and TimeStamp */ + buf->wDuration_a = s_uGetDataDuration(priv, pkt_type, need_ack); + buf->wDuration_b = s_uGetDataDuration(priv, PK_TYPE_11B, need_ack); - case CTSDUR_BA_F0: //CTSDuration_ba_f0 - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck); - } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); - } - break; + buf->wTimeStampOff_a = vnt_time_stamp_off(priv, rate); + buf->wTimeStampOff_b = vnt_time_stamp_off(priv, + priv->byTopCCKBasicRate); - case CTSDUR_BA_F1: //CTSDuration_ba_f1 - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck); - } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck); - } - break; + return buf->wDuration_a; +} - default: - break; - } +static u16 vnt_rxtx_datahead_g_fb(struct vnt_private *priv, u8 pkt_type, + u16 rate, struct vnt_tx_datahead_g_fb *buf, + u32 frame_len, int need_ack) +{ + /* Get SignalField,ServiceField,Length */ + BBvCalculateParameter(priv, frame_len, rate, pkt_type, &buf->a); - return cpu_to_le16((u16)uDurTime); + BBvCalculateParameter(priv, frame_len, priv->byTopCCKBasicRate, + PK_TYPE_11B, &buf->b); + + /* Get Duration and TimeStamp */ + buf->wDuration_a = s_uGetDataDuration(priv, pkt_type, need_ack); + buf->wDuration_b = s_uGetDataDuration(priv, PK_TYPE_11B, need_ack); + + buf->wDuration_a_f0 = s_uGetDataDuration(priv, pkt_type, need_ack); + buf->wDuration_a_f1 = s_uGetDataDuration(priv, pkt_type, need_ack); + + buf->wTimeStampOff_a = vnt_time_stamp_off(priv, rate); + buf->wTimeStampOff_b = vnt_time_stamp_off(priv, + priv->byTopCCKBasicRate); + + return buf->wDuration_a; } -static u32 s_uFillDataHead(struct vnt_private *pDevice, - u8 byPktType, u16 wCurrentRate, void *pTxDataHead, u32 cbFrameLength, - u32 uDMAIdx, int bNeedAck, u8 byFBOption) +static u16 vnt_rxtx_datahead_a_fb(struct vnt_private *priv, u8 pkt_type, + u16 rate, struct vnt_tx_datahead_a_fb *buf, + u32 frame_len, int need_ack) { + /* Get SignalField,ServiceField,Length */ + BBvCalculateParameter(priv, frame_len, rate, pkt_type, &buf->a); + /* Get Duration and TimeStampOff */ + buf->wDuration = s_uGetDataDuration(priv, pkt_type, need_ack); - if (pTxDataHead == NULL) { - return 0; - } + buf->wDuration_f0 = s_uGetDataDuration(priv, pkt_type, need_ack); + buf->wDuration_f1 = s_uGetDataDuration(priv, pkt_type, need_ack); - if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - if (byFBOption == AUTO_FB_NONE) { - struct vnt_tx_datahead_g *pBuf = - (struct vnt_tx_datahead_g *)pTxDataHead; - //Get SignalField,ServiceField,Length - BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, - byPktType, &pBuf->a); - BBvCalculateParameter(pDevice, cbFrameLength, - pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b); - //Get Duration and TimeStamp - pBuf->wDuration_a = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wDuration_b = s_uGetDataDuration(pDevice, - PK_TYPE_11B, bNeedAck); - - pBuf->wTimeStampOff_a = vnt_time_stamp_off(pDevice, - wCurrentRate); - pBuf->wTimeStampOff_b = vnt_time_stamp_off(pDevice, - pDevice->byTopCCKBasicRate); - return (pBuf->wDuration_a); - } else { - // Auto Fallback - struct vnt_tx_datahead_g_fb *pBuf = - (struct vnt_tx_datahead_g_fb *)pTxDataHead; - //Get SignalField,ServiceField,Length - BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, - byPktType, &pBuf->a); - BBvCalculateParameter(pDevice, cbFrameLength, - pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b); - //Get Duration and TimeStamp - pBuf->wDuration_a = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wDuration_b = s_uGetDataDuration(pDevice, - PK_TYPE_11B, bNeedAck); - pBuf->wDuration_a_f0 = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wDuration_a_f1 = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wTimeStampOff_a = vnt_time_stamp_off(pDevice, - wCurrentRate); - pBuf->wTimeStampOff_b = vnt_time_stamp_off(pDevice, - pDevice->byTopCCKBasicRate); - return (pBuf->wDuration_a); - } //if (byFBOption == AUTO_FB_NONE) - } - else if (byPktType == PK_TYPE_11A) { - if (byFBOption != AUTO_FB_NONE) { - struct vnt_tx_datahead_a_fb *pBuf = - (struct vnt_tx_datahead_a_fb *)pTxDataHead; - //Get SignalField,ServiceField,Length - BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, - byPktType, &pBuf->a); - //Get Duration and TimeStampOff - pBuf->wDuration = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wDuration_f0 = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wDuration_f1 = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice, - wCurrentRate); - return (pBuf->wDuration); - } else { - struct vnt_tx_datahead_ab *pBuf = - (struct vnt_tx_datahead_ab *)pTxDataHead; - //Get SignalField,ServiceField,Length - BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, - byPktType, &pBuf->ab); - //Get Duration and TimeStampOff - pBuf->wDuration = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice, - wCurrentRate); - return (pBuf->wDuration); - } - } - else if (byPktType == PK_TYPE_11B) { - struct vnt_tx_datahead_ab *pBuf = - (struct vnt_tx_datahead_ab *)pTxDataHead; - //Get SignalField,ServiceField,Length - BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, - byPktType, &pBuf->ab); - //Get Duration and TimeStampOff - pBuf->wDuration = s_uGetDataDuration(pDevice, - byPktType, bNeedAck); - pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice, - wCurrentRate); - return (pBuf->wDuration); - } - return 0; + buf->wTimeStampOff = vnt_time_stamp_off(priv, rate); + + return buf->wDuration; +} + +static u16 vnt_rxtx_datahead_ab(struct vnt_private *priv, u8 pkt_type, + u16 rate, struct vnt_tx_datahead_ab *buf, + u32 frame_len, int need_ack) +{ + /* Get SignalField,ServiceField,Length */ + BBvCalculateParameter(priv, frame_len, rate, pkt_type, &buf->ab); + /* Get Duration and TimeStampOff */ + buf->wDuration = s_uGetDataDuration(priv, pkt_type, need_ack); + + buf->wTimeStampOff = vnt_time_stamp_off(priv, rate); + + return buf->wDuration; } static int vnt_fill_ieee80211_rts(struct vnt_private *priv, @@ -632,7 +560,7 @@ static int vnt_fill_ieee80211_rts(struct vnt_private *priv, return 0; } -static int vnt_rxtx_rts_g_head(struct vnt_private *priv, +static u16 vnt_rxtx_rts_g_head(struct vnt_private *priv, struct vnt_rts_g *buf, struct ethhdr *eth_hdr, u8 pkt_type, u32 frame_len, int need_ack, u16 current_rate, u8 fb_option) @@ -653,10 +581,11 @@ static int vnt_rxtx_rts_g_head(struct vnt_private *priv, vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration_aa); - return 0; + return vnt_rxtx_datahead_g(priv, pkt_type, current_rate, + &buf->data_head, frame_len, need_ack); } -static int vnt_rxtx_rts_g_fb_head(struct vnt_private *priv, +static u16 vnt_rxtx_rts_g_fb_head(struct vnt_private *priv, struct vnt_rts_g_fb *buf, struct ethhdr *eth_hdr, u8 pkt_type, u32 frame_len, int need_ack, u16 current_rate, u8 fb_option) @@ -678,20 +607,21 @@ static int vnt_rxtx_rts_g_fb_head(struct vnt_private *priv, buf->wRTSDuration_ba_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F0, - frame_len, pkt_type, current_rate, need_ack, fb_option); + frame_len, pkt_type, priv->tx_rate_fb0, need_ack, fb_option); buf->wRTSDuration_aa_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0, - frame_len, pkt_type, current_rate, need_ack, fb_option); + frame_len, pkt_type, priv->tx_rate_fb0, need_ack, fb_option); buf->wRTSDuration_ba_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F1, - frame_len, pkt_type, current_rate, need_ack, fb_option); + frame_len, pkt_type, priv->tx_rate_fb1, need_ack, fb_option); buf->wRTSDuration_aa_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1, - frame_len, pkt_type, current_rate, need_ack, fb_option); + frame_len, pkt_type, priv->tx_rate_fb1, need_ack, fb_option); vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration_aa); - return 0; + return vnt_rxtx_datahead_g_fb(priv, pkt_type, current_rate, + &buf->data_head, frame_len, need_ack); } -static int vnt_rxtx_rts_ab_head(struct vnt_private *priv, +static u16 vnt_rxtx_rts_ab_head(struct vnt_private *priv, struct vnt_rts_ab *buf, struct ethhdr *eth_hdr, u8 pkt_type, u32 frame_len, int need_ack, u16 current_rate, u8 fb_option) @@ -706,10 +636,11 @@ static int vnt_rxtx_rts_ab_head(struct vnt_private *priv, vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration); - return 0; + return vnt_rxtx_datahead_ab(priv, pkt_type, current_rate, + &buf->data_head, frame_len, need_ack); } -static int vnt_rxtx_rts_a_fb_head(struct vnt_private *priv, +static u16 vnt_rxtx_rts_a_fb_head(struct vnt_private *priv, struct vnt_rts_a_fb *buf, struct ethhdr *eth_hdr, u8 pkt_type, u32 frame_len, int need_ack, u16 current_rate, u8 fb_option) @@ -723,23 +654,24 @@ static int vnt_rxtx_rts_a_fb_head(struct vnt_private *priv, pkt_type, current_rate, need_ack, fb_option); buf->wRTSDuration_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0, - frame_len, pkt_type, current_rate, need_ack, fb_option); + frame_len, pkt_type, priv->tx_rate_fb0, need_ack, fb_option); buf->wRTSDuration_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1, - frame_len, pkt_type, current_rate, need_ack, fb_option); + frame_len, pkt_type, priv->tx_rate_fb1, need_ack, fb_option); vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration); - return 0; + return vnt_rxtx_datahead_a_fb(priv, pkt_type, current_rate, + &buf->data_head, frame_len, need_ack); } -static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType, +static u16 s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType, union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck, struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption) { if (!head) - return; + return 0; /* Note: So far RTSHead doesn't appear in ATIM * & Beacom DMA, so we don't need to take them @@ -750,36 +682,38 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType, case PK_TYPE_11GB: case PK_TYPE_11GA: if (byFBOption == AUTO_FB_NONE) - vnt_rxtx_rts_g_head(pDevice, &head->rts_g, + return vnt_rxtx_rts_g_head(pDevice, &head->rts_g, psEthHeader, byPktType, cbFrameLength, bNeedAck, wCurrentRate, byFBOption); else - vnt_rxtx_rts_g_fb_head(pDevice, &head->rts_g_fb, + return vnt_rxtx_rts_g_fb_head(pDevice, &head->rts_g_fb, psEthHeader, byPktType, cbFrameLength, bNeedAck, wCurrentRate, byFBOption); break; case PK_TYPE_11A: if (byFBOption) { - vnt_rxtx_rts_a_fb_head(pDevice, &head->rts_a_fb, + return vnt_rxtx_rts_a_fb_head(pDevice, &head->rts_a_fb, psEthHeader, byPktType, cbFrameLength, bNeedAck, wCurrentRate, byFBOption); break; } case PK_TYPE_11B: - vnt_rxtx_rts_ab_head(pDevice, &head->rts_ab, + return vnt_rxtx_rts_ab_head(pDevice, &head->rts_ab, psEthHeader, byPktType, cbFrameLength, bNeedAck, wCurrentRate, byFBOption); } + + return 0; } -static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, +static u16 s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, u8 byPktType, union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck, u16 wCurrentRate, u8 byFBOption) { u32 uCTSFrameLen = 14; if (!head) - return; + return 0; if (byFBOption != AUTO_FB_NONE) { /* Auto Fall back */ @@ -792,16 +726,19 @@ static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, wCurrentRate, bNeedAck, byFBOption); /* Get CTSDuration_ba_f0 */ pBuf->wCTSDuration_ba_f0 = s_uGetRTSCTSDuration(pDevice, - CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, - bNeedAck, byFBOption); + CTSDUR_BA_F0, cbFrameLength, byPktType, + pDevice->tx_rate_fb0, bNeedAck, byFBOption); /* Get CTSDuration_ba_f1 */ pBuf->wCTSDuration_ba_f1 = s_uGetRTSCTSDuration(pDevice, - CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, - bNeedAck, byFBOption); + CTSDUR_BA_F1, cbFrameLength, byPktType, + pDevice->tx_rate_fb1, bNeedAck, byFBOption); /* Get CTS Frame body */ pBuf->data.duration = pBuf->wDuration_ba; pBuf->data.frame_control = TYPE_CTL_CTS; memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN); + + return vnt_rxtx_datahead_g_fb(pDevice, byPktType, wCurrentRate, + &pBuf->data_head, cbFrameLength, bNeedAck); } else { struct vnt_cts *pBuf = &head->cts_g; /* Get SignalField,ServiceField,Length */ @@ -815,7 +752,12 @@ static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, pBuf->data.duration = pBuf->wDuration_ba; pBuf->data.frame_control = TYPE_CTL_CTS; memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN); + + return vnt_rxtx_datahead_g(pDevice, byPktType, wCurrentRate, + &pBuf->data_head, cbFrameLength, bNeedAck); } + + return 0; } /*+ @@ -841,112 +783,160 @@ static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx, * -*/ -static void s_vGenerateTxParameter(struct vnt_private *pDevice, - u8 byPktType, u16 wCurrentRate, void *pTxBufHead, void *pvRrvTime, - void *rts_cts, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx, - struct ethhdr *psEthHeader, bool need_rts) +static u16 s_vGenerateTxParameter(struct vnt_private *pDevice, + u8 byPktType, u16 wCurrentRate, struct vnt_tx_buffer *tx_buffer, + struct vnt_mic_hdr **mic_hdr, u32 need_mic, u32 cbFrameSize, + int bNeedACK, u32 uDMAIdx, struct ethhdr *psEthHeader, bool need_rts) { - union vnt_tx_data_head *head = rts_cts; + struct vnt_tx_fifo_head *pFifoHead = &tx_buffer->fifo_head; + union vnt_tx_data_head *head = NULL; u32 cbMACHdLen = WLAN_HDR_ADDR3_LEN; /* 24 */ u16 wFifoCtl; u8 byFBOption = AUTO_FB_NONE; - //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter...\n"); - PSTxBufHead pFifoHead = (PSTxBufHead)pTxBufHead; - pFifoHead->wReserved = wCurrentRate; - wFifoCtl = pFifoHead->wFIFOCtl; + pFifoHead->wReserved = wCurrentRate; + wFifoCtl = pFifoHead->wFIFOCtl; - if (wFifoCtl & FIFOCTL_AUTO_FB_0) { - byFBOption = AUTO_FB_0; - } - else if (wFifoCtl & FIFOCTL_AUTO_FB_1) { - byFBOption = AUTO_FB_1; - } + if (wFifoCtl & FIFOCTL_AUTO_FB_0) + byFBOption = AUTO_FB_0; + else if (wFifoCtl & FIFOCTL_AUTO_FB_1) + byFBOption = AUTO_FB_1; - if (!pvRrvTime) - return; + if (!pFifoHead) + return 0; - if (pDevice->bLongHeader) - cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6; + if (pDevice->bLongHeader) + cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6; - if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - if (need_rts) { - //Fill RsvTime - struct vnt_rrv_time_rts *pBuf = - (struct vnt_rrv_time_rts *)pvRrvTime; - pBuf->wRTSTxRrvTime_aa = s_uGetRTSCTSRsvTime(pDevice, 2, - byPktType, cbFrameSize, wCurrentRate); - pBuf->wRTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 1, - byPktType, cbFrameSize, wCurrentRate); - pBuf->wRTSTxRrvTime_bb = s_uGetRTSCTSRsvTime(pDevice, 0, - byPktType, cbFrameSize, wCurrentRate); - pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice, - byPktType, cbFrameSize, wCurrentRate, bNeedACK); - pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice, - PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, - bNeedACK); - /* Fill RTS */ - s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize, - bNeedACK, psEthHeader, wCurrentRate, byFBOption); - } - else {//RTS_needless, PCF mode - //Fill RsvTime - struct vnt_rrv_time_cts *pBuf = - (struct vnt_rrv_time_cts *)pvRrvTime; - pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice, byPktType, - cbFrameSize, wCurrentRate, bNeedACK); - pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice, - PK_TYPE_11B, cbFrameSize, - pDevice->byTopCCKBasicRate, bNeedACK); - pBuf->wCTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 3, + if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { + if (need_rts) { + struct vnt_rrv_time_rts *pBuf = + &tx_buffer->tx_head.tx_rts.rts; + + pBuf->wRTSTxRrvTime_aa = s_uGetRTSCTSRsvTime(pDevice, 2, + byPktType, cbFrameSize, wCurrentRate); + pBuf->wRTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 1, + byPktType, cbFrameSize, wCurrentRate); + pBuf->wRTSTxRrvTime_bb = s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate); - /* Fill CTS */ - s_vFillCTSHead(pDevice, uDMAIdx, byPktType, head, - cbFrameSize, bNeedACK, wCurrentRate, byFBOption); - } - } - else if (byPktType == PK_TYPE_11A) { - if (need_rts) { - //Fill RsvTime - struct vnt_rrv_time_ab *pBuf = - (struct vnt_rrv_time_ab *)pvRrvTime; - pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 2, + + pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice, + byPktType, cbFrameSize, wCurrentRate, bNeedACK); + pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice, + PK_TYPE_11B, cbFrameSize, + pDevice->byTopCCKBasicRate, bNeedACK); + + if (need_mic) { + *mic_hdr = &tx_buffer-> + tx_head.tx_rts.tx.mic.hdr; + head = &tx_buffer->tx_head.tx_rts.tx.mic.head; + } else { + head = &tx_buffer->tx_head.tx_rts.tx.head; + } + + /* Fill RTS */ + return s_vFillRTSHead(pDevice, byPktType, head, + cbFrameSize, bNeedACK, psEthHeader, + wCurrentRate, byFBOption); + + } else { + struct vnt_rrv_time_cts *pBuf = &tx_buffer-> + tx_head.tx_cts.cts; + + pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice, + byPktType, cbFrameSize, wCurrentRate, bNeedACK); + pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice, + PK_TYPE_11B, cbFrameSize, + pDevice->byTopCCKBasicRate, bNeedACK); + + pBuf->wCTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 3, + byPktType, cbFrameSize, wCurrentRate); + + if (need_mic) { + *mic_hdr = &tx_buffer-> + tx_head.tx_cts.tx.mic.hdr; + head = &tx_buffer->tx_head.tx_cts.tx.mic.head; + } else { + head = &tx_buffer->tx_head.tx_cts.tx.head; + } + + /* Fill CTS */ + return s_vFillCTSHead(pDevice, uDMAIdx, byPktType, + head, cbFrameSize, bNeedACK, wCurrentRate, + byFBOption); + } + } else if (byPktType == PK_TYPE_11A) { + if (need_mic) { + *mic_hdr = &tx_buffer->tx_head.tx_ab.tx.mic.hdr; + head = &tx_buffer->tx_head.tx_ab.tx.mic.head; + } else { + head = &tx_buffer->tx_head.tx_ab.tx.head; + } + + if (need_rts) { + struct vnt_rrv_time_ab *pBuf = &tx_buffer-> + tx_head.tx_ab.ab; + + pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate); - pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, byPktType, - cbFrameSize, wCurrentRate, bNeedACK); - /* Fill RTS */ - s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize, - bNeedACK, psEthHeader, wCurrentRate, byFBOption); - } else { - //Fill RsvTime - struct vnt_rrv_time_ab *pBuf = - (struct vnt_rrv_time_ab *)pvRrvTime; - pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11A, - cbFrameSize, wCurrentRate, bNeedACK); - } - } - else if (byPktType == PK_TYPE_11B) { - if (need_rts) { - //Fill RsvTime - struct vnt_rrv_time_ab *pBuf = - (struct vnt_rrv_time_ab *)pvRrvTime; - pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 0, + + pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, + byPktType, cbFrameSize, wCurrentRate, bNeedACK); + + /* Fill RTS */ + return s_vFillRTSHead(pDevice, byPktType, head, + cbFrameSize, bNeedACK, psEthHeader, + wCurrentRate, byFBOption); + } else { + struct vnt_rrv_time_ab *pBuf = &tx_buffer-> + tx_head.tx_ab.ab; + + pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, + PK_TYPE_11A, cbFrameSize, + wCurrentRate, bNeedACK); + + return vnt_rxtx_datahead_a_fb(pDevice, byPktType, + wCurrentRate, &head->data_head_a_fb, + cbFrameSize, bNeedACK); + } + } else if (byPktType == PK_TYPE_11B) { + if (need_mic) { + *mic_hdr = &tx_buffer->tx_head.tx_ab.tx.mic.hdr; + head = &tx_buffer->tx_head.tx_ab.tx.mic.head; + } else { + head = &tx_buffer->tx_head.tx_ab.tx.head; + } + + if (need_rts) { + struct vnt_rrv_time_ab *pBuf = &tx_buffer-> + tx_head.tx_ab.ab; + + pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate); - pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B, - cbFrameSize, wCurrentRate, bNeedACK); - /* Fill RTS */ - s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize, + + pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, + PK_TYPE_11B, cbFrameSize, wCurrentRate, + bNeedACK); + + /* Fill RTS */ + return s_vFillRTSHead(pDevice, byPktType, head, + cbFrameSize, bNeedACK, psEthHeader, wCurrentRate, byFBOption); - } - else { //RTS_needless, non PCF mode - //Fill RsvTime - struct vnt_rrv_time_ab *pBuf = - (struct vnt_rrv_time_ab *)pvRrvTime; - pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B, - cbFrameSize, wCurrentRate, bNeedACK); - } - } - //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter END.\n"); + } else { + struct vnt_rrv_time_ab *pBuf = &tx_buffer-> + tx_head.tx_ab.ab; + + pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, + PK_TYPE_11B, cbFrameSize, + wCurrentRate, bNeedACK); + + return vnt_rxtx_datahead_ab(pDevice, byPktType, + wCurrentRate, &head->data_head_ab, + cbFrameSize, bNeedACK); + } + } + + return 0; } /* u8 * pbyBuffer,//point to pTxBufHead @@ -955,11 +945,12 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice, */ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType, - struct vnt_tx_buffer *pTxBufHead, int bNeedEncryption, + struct vnt_tx_buffer *tx_buffer, int bNeedEncryption, u32 uSkbPacketLen, u32 uDMAIdx, struct ethhdr *psEthHeader, u8 *pPacket, PSKeyItem pTransmitKey, u32 uNodeIndex, u16 wCurrentRate, u32 *pcbHeaderLen, u32 *pcbTotalLen) { + struct vnt_tx_fifo_head *pTxBufHead = &tx_buffer->fifo_head; struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; u32 cbFrameSize, cbFrameBodySize; u32 cb802_1_H_len; @@ -973,17 +964,14 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType, = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8}; u32 uDuration; u32 cbHeaderLength = 0, uPadding = 0; - void *pvRrvTime; struct vnt_mic_hdr *pMICHDR; - void *rts_cts = NULL; - void *pvTxDataHd; u8 byFBOption = AUTO_FB_NONE, byFragType; u16 wTxBufSize; u32 dwMICKey0, dwMICKey1, dwMIC_Priority; u32 *pdwMIC_L, *pdwMIC_R; int bSoftWEP = false; - pvRrvTime = pMICHDR = pvTxDataHd = NULL; + pMICHDR = NULL; if (bNeedEncryption && pTransmitKey->pvKeyTable) { if (((PSKeyTable)pTransmitKey->pvKeyTable)->bSoftWEP == true) @@ -1047,16 +1035,27 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType, pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK; } - //Set Auto Fallback Ctl - if (wCurrentRate >= RATE_18M) { - if (pDevice->byAutoFBCtrl == AUTO_FB_0) { - pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_0; - byFBOption = AUTO_FB_0; - } else if (pDevice->byAutoFBCtrl == AUTO_FB_1) { - pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_1; - byFBOption = AUTO_FB_1; - } - } + /* Set Auto Fallback Ctl */ + if (wCurrentRate >= RATE_18M) { + if (pDevice->byAutoFBCtrl == AUTO_FB_0) { + pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_0; + + pDevice->tx_rate_fb0 = + wFB_Opt0[FB_RATE0][wCurrentRate - RATE_18M]; + pDevice->tx_rate_fb1 = + wFB_Opt0[FB_RATE1][wCurrentRate - RATE_18M]; + + byFBOption = AUTO_FB_0; + } else if (pDevice->byAutoFBCtrl == AUTO_FB_1) { + pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_1; + pDevice->tx_rate_fb0 = + wFB_Opt1[FB_RATE0][wCurrentRate - RATE_18M]; + pDevice->tx_rate_fb1 = + wFB_Opt1[FB_RATE1][wCurrentRate - RATE_18M]; + + byFBOption = AUTO_FB_1; + } + } if (bSoftWEP != true) { if ((bNeedEncryption) && (pTransmitKey != NULL)) { //WEP enabled @@ -1105,118 +1104,47 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType, } pbyTxBufferAddr = (u8 *) &(pTxBufHead->adwTxKey[0]); - wTxBufSize = sizeof(STxBufHead); + wTxBufSize = sizeof(struct vnt_tx_fifo_head); + if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet if (byFBOption == AUTO_FB_NONE) { if (bRTS == true) {//RTS_need - pvRrvTime = (struct vnt_rrv_time_rts *) - (pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_rts)); - rts_cts = (struct vnt_rts_g *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_rts) + cbMICHDR); - pvTxDataHd = (struct vnt_tx_datahead_g *) (pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_rts) + - cbMICHDR + sizeof(struct vnt_rts_g)); cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_rts) + - cbMICHDR + sizeof(struct vnt_rts_g) + - sizeof(struct vnt_tx_datahead_g); + cbMICHDR + sizeof(struct vnt_rts_g); } else { //RTS_needless - pvRrvTime = (struct vnt_rrv_time_cts *) - (pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts)); - rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts) + cbMICHDR); - pvTxDataHd = (struct vnt_tx_datahead_g *)(pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_cts) + - cbMICHDR + sizeof(struct vnt_cts)); cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_cts) + - cbMICHDR + sizeof(struct vnt_cts) + - sizeof(struct vnt_tx_datahead_g); + cbMICHDR + sizeof(struct vnt_cts); } } else { // Auto Fall Back if (bRTS == true) {//RTS_need - pvRrvTime = (struct vnt_rrv_time_rts *)(pbyTxBufferAddr + - wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_rts)); - rts_cts = (struct vnt_rts_g_fb *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_rts) + cbMICHDR); - pvTxDataHd = (struct vnt_tx_datahead_g_fb *) (pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_rts) + - cbMICHDR + sizeof(struct vnt_rts_g_fb)); cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_rts) + - cbMICHDR + sizeof(struct vnt_rts_g_fb) + - sizeof(struct vnt_tx_datahead_g_fb); + cbMICHDR + sizeof(struct vnt_rts_g_fb); } else if (bRTS == false) { //RTS_needless - pvRrvTime = (struct vnt_rrv_time_cts *) - (pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts)); - rts_cts = (struct vnt_cts_fb *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts) + cbMICHDR); - pvTxDataHd = (struct vnt_tx_datahead_g_fb *) (pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_cts) + - cbMICHDR + sizeof(struct vnt_cts_fb)); cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_cts) + - cbMICHDR + sizeof(struct vnt_cts_fb) + - sizeof(struct vnt_tx_datahead_g_fb); + cbMICHDR + sizeof(struct vnt_cts_fb); } } // Auto Fall Back } else {//802.11a/b packet if (byFBOption == AUTO_FB_NONE) { if (bRTS == true) {//RTS_need - pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr + - wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab)); - rts_cts = (struct vnt_rts_ab *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab) + cbMICHDR); - pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR + - sizeof(struct vnt_rts_ab)); cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + - cbMICHDR + sizeof(struct vnt_rts_ab) + - sizeof(struct vnt_tx_datahead_ab); + cbMICHDR + sizeof(struct vnt_rts_ab); } else if (bRTS == false) { //RTS_needless, no MICHDR - pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr + - wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab)); - pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR); cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR + sizeof(struct vnt_tx_datahead_ab); } } else { // Auto Fall Back if (bRTS == true) {//RTS_need - pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr + - wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab)); - rts_cts = (struct vnt_rts_a_fb *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab) + cbMICHDR); - pvTxDataHd = (struct vnt_tx_datahead_a_fb *)(pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR + - sizeof(struct vnt_rts_a_fb)); cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + - cbMICHDR + sizeof(struct vnt_rts_a_fb) + - sizeof(struct vnt_tx_datahead_a_fb); + cbMICHDR + sizeof(struct vnt_rts_a_fb); } else if (bRTS == false) { //RTS_needless - pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr + - wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab)); - pvTxDataHd = (struct vnt_tx_datahead_a_fb *)(pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR); cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR + sizeof(struct vnt_tx_datahead_a_fb); } @@ -1235,20 +1163,18 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType, //uDMAIdx = TYPE_AC0DMA; //pTxBufHead = (PSTxBufHead) &(pTxBufHead->adwTxKey[0]); - //Fill FIFO,RrvTime,RTS,and CTS - s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, - (void *)pbyTxBufferAddr, pvRrvTime, rts_cts, - cbFrameSize, bNeedACK, uDMAIdx, psEthHeader, bRTS); - //Fill DataHead - uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, uDMAIdx, bNeedACK, - byFBOption); + /* Fill FIFO, RrvTime, RTS and CTS */ + uDuration = s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, + tx_buffer, &pMICHDR, cbMICHDR, + cbFrameSize, bNeedACK, uDMAIdx, psEthHeader, bRTS); + // Generate TX MAC Header s_vGenerateMACHeader(pDevice, pbyMacHdr, (u16)uDuration, psEthHeader, bNeedEncryption, byFragType, uDMAIdx, 0); if (bNeedEncryption == true) { //Fill TXKEY - s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey, + s_vFillTxKey(pDevice, pTxBufHead, pbyIVHead, pTransmitKey, pbyMacHdr, (u16)cbFrameBodySize, pMICHDR); if (pDevice->bEnableHostWEP) { @@ -1469,13 +1395,12 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, { struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; struct vnt_tx_buffer *pTX_Buffer; - PSTxBufHead pTxBufHead; struct vnt_usb_send_context *pContext; + struct vnt_tx_fifo_head *pTxBufHead; struct ieee80211_hdr *pMACHeader; struct ethhdr sEthHeader; u8 byPktType, *pbyTxBufferAddr; - void *rts_cts = NULL; - void *pvTxDataHd, *pvRrvTime, *pMICHDR; + struct vnt_mic_hdr *pMICHDR = NULL; u32 uDuration, cbReqCount, cbHeaderSize, cbFrameBodySize, cbFrameSize; int bNeedACK, bIsPSPOLL = false; u32 cbIVlen = 0, cbICVlen = 0, cbMIClen = 0, cbFCSlen = 4; @@ -1492,10 +1417,10 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, } pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0]; - pbyTxBufferAddr = (u8 *)&(pTX_Buffer->adwTxKey[0]); cbFrameBodySize = pPacket->cbPayloadLen; - pTxBufHead = (PSTxBufHead) pbyTxBufferAddr; - wTxBufSize = sizeof(STxBufHead); + pTxBufHead = &pTX_Buffer->fifo_head; + pbyTxBufferAddr = (u8 *)&pTxBufHead->adwTxKey[0]; + wTxBufSize = sizeof(struct vnt_tx_fifo_head); if (pDevice->byBBType == BB_TYPE_11A) { wCurrentRate = RATE_6M; @@ -1607,21 +1532,10 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, //Set RrvTime/RTS/CTS Buffer if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet - - pvRrvTime = (struct vnt_rrv_time_cts *) (pbyTxBufferAddr + wTxBufSize); - pMICHDR = NULL; - rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts)); - pvTxDataHd = (struct vnt_tx_datahead_g *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts) + sizeof(struct vnt_cts)); cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_cts) + - sizeof(struct vnt_cts) + sizeof(struct vnt_tx_datahead_g); + sizeof(struct vnt_cts); } else { // 802.11a/b packet - pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr + wTxBufSize); - pMICHDR = NULL; - pvTxDataHd = (struct vnt_tx_datahead_ab *) (pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_ab)); cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + sizeof(struct vnt_tx_datahead_ab); } @@ -1638,14 +1552,10 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, pTxBufHead->wFragCtl |= (u16)FRAGCTL_NONFRAG; /* Fill FIFO,RrvTime,RTS,and CTS */ - s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, - pbyTxBufferAddr, pvRrvTime, rts_cts, + uDuration = s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, + pTX_Buffer, &pMICHDR, 0, cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, false); - //Fill DataHead - uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK, - AUTO_FB_NONE); - pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize); cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + cbFrameBodySize; @@ -1684,7 +1594,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, } } while(false); //Fill TXKEY - s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey, + s_vFillTxKey(pDevice, pTxBufHead, pbyIVHead, pTransmitKey, (u8 *)pMACHeader, (u16)cbFrameBodySize, NULL); memcpy(pMACHeader, pPacket->p80211Header, cbMacHdLen); @@ -1708,12 +1618,16 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, // in the same place of other packet's Duration-field). // And it will cause Cisco-AP to issue Disassociation-packet if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - ((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_a = + struct vnt_tx_datahead_g *data_head = &pTX_Buffer->tx_head. + tx_cts.tx.head.cts_g.data_head; + data_head->wDuration_a = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID); - ((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_b = + data_head->wDuration_b = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID); } else { - ((struct vnt_tx_datahead_ab *)pvTxDataHd)->wDuration = + struct vnt_tx_datahead_ab *data_head = &pTX_Buffer->tx_head. + tx_ab.tx.head.data_head_ab; + data_head->wDuration = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID); } } @@ -1727,10 +1641,14 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, pContext->uBufLen = (u16)cbReqCount + 4; //USB header if (WLAN_GET_FC_TODS(pMACHeader->frame_control) == 0) { - s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->addr1[0]), (u16)cbFrameSize, pTX_Buffer->wFIFOCtl); + s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F), + &pMACHeader->addr1[0], (u16)cbFrameSize, + pTxBufHead->wFIFOCtl); } else { - s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->addr3[0]), (u16)cbFrameSize, pTX_Buffer->wFIFOCtl); + s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F), + &pMACHeader->addr3[0], (u16)cbFrameSize, + pTxBufHead->wFIFOCtl); } PIPEnsSendBulkOut(pDevice,pContext); @@ -1825,15 +1743,13 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) { struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; struct vnt_tx_buffer *pTX_Buffer; + struct vnt_tx_fifo_head *pTxBufHead; u8 byPktType; u8 *pbyTxBufferAddr; - void *rts_cts = NULL; - void *pvTxDataHd; u32 uDuration, cbReqCount; struct ieee80211_hdr *pMACHeader; u32 cbHeaderSize, cbFrameBodySize; int bNeedACK, bIsPSPOLL = false; - PSTxBufHead pTxBufHead; u32 cbFrameSize; u32 cbIVlen = 0, cbICVlen = 0, cbMIClen = 0, cbFCSlen = 4; u32 uPadding = 0; @@ -1844,7 +1760,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) u16 wTxBufSize; u32 cbMacHdLen; struct ethhdr sEthHeader; - void *pvRrvTime, *pMICHDR; + struct vnt_mic_hdr *pMICHDR; u32 wCurrentRate = RATE_1M; PUWLAN_80211HDR p80211Header; u32 uNodeIndex = 0; @@ -1855,7 +1771,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) u32 cbExtSuppRate = 0; struct vnt_usb_send_context *pContext; - pvRrvTime = pMICHDR = pvTxDataHd = NULL; + pMICHDR = NULL; if(skb->len <= WLAN_HDR_ADDR3_LEN) { cbFrameBodySize = 0; @@ -1874,9 +1790,9 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) } pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0]; - pbyTxBufferAddr = (u8 *)(&pTX_Buffer->adwTxKey[0]); - pTxBufHead = (PSTxBufHead) pbyTxBufferAddr; - wTxBufSize = sizeof(STxBufHead); + pTxBufHead = &pTX_Buffer->fifo_head; + pbyTxBufferAddr = (u8 *)&pTxBufHead->adwTxKey[0]; + wTxBufSize = sizeof(struct vnt_tx_fifo_head); if (pDevice->byBBType == BB_TYPE_11A) { wCurrentRate = RATE_6M; @@ -2014,25 +1930,11 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) //the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter() if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet - pvRrvTime = (struct vnt_rrv_time_cts *) (pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts)); - rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts) + cbMICHDR); - pvTxDataHd = (struct vnt_tx_datahead_g *) (pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR + - sizeof(struct vnt_cts)); cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR + - sizeof(struct vnt_cts) + sizeof(struct vnt_tx_datahead_g); + sizeof(struct vnt_cts); } else {//802.11a/b packet - - pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab)); - pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr + - wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR); cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR + sizeof(struct vnt_tx_datahead_ab); } @@ -2048,15 +1950,11 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) pTxBufHead->wFragCtl |= (u16)FRAGCTL_NONFRAG; /* Fill FIFO,RrvTime,RTS,and CTS */ - s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, - pbyTxBufferAddr, pvRrvTime, rts_cts, + uDuration = s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, + pTX_Buffer, &pMICHDR, cbMICHDR, cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, false); - //Fill DataHead - uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK, - AUTO_FB_NONE); - - pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize); + pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize); cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen) + cbExtSuppRate; @@ -2139,7 +2037,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) } - s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey, + s_vFillTxKey(pDevice, pTxBufHead, pbyIVHead, pTransmitKey, pbyMacHdr, (u16)cbFrameBodySize, pMICHDR); if (pDevice->bEnableHostWEP) { @@ -2164,12 +2062,16 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) // in the same place of other packet's Duration-field). // And it will cause Cisco-AP to issue Disassociation-packet if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - ((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_a = + struct vnt_tx_datahead_g *data_head = &pTX_Buffer->tx_head. + tx_cts.tx.head.cts_g.data_head; + data_head->wDuration_a = cpu_to_le16(p80211Header->sA2.wDurationID); - ((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_b = + data_head->wDuration_b = cpu_to_le16(p80211Header->sA2.wDurationID); } else { - ((struct vnt_tx_datahead_ab *)pvTxDataHd)->wDuration = + struct vnt_tx_datahead_ab *data_head = &pTX_Buffer->tx_head. + tx_ab.tx.head.data_head_ab; + data_head->wDuration = cpu_to_le16(p80211Header->sA2.wDurationID); } } @@ -2183,10 +2085,14 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) pContext->uBufLen = (u16)cbReqCount + 4; //USB header if (WLAN_GET_FC_TODS(pMACHeader->frame_control) == 0) { - s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->addr1[0]), (u16)cbFrameSize, pTX_Buffer->wFIFOCtl); + s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F), + &pMACHeader->addr1[0], (u16)cbFrameSize, + pTxBufHead->wFIFOCtl); } else { - s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->addr3[0]), (u16)cbFrameSize, pTX_Buffer->wFIFOCtl); + s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F), + &pMACHeader->addr3[0], (u16)cbFrameSize, + pTxBufHead->wFIFOCtl); } PIPEnsSendBulkOut(pDevice,pContext); return ; @@ -2568,7 +2474,10 @@ int nsDMA_tx_packet(struct vnt_private *pDevice, pContext->Type = CONTEXT_DATA_PACKET; pContext->uBufLen = (u16)BytesToWrite + 4 ; //USB header - s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pContext->sEthHeader.h_dest[0]), (u16) (BytesToWrite-uHeaderLen), pTX_Buffer->wFIFOCtl); + s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F), + &pContext->sEthHeader.h_dest[0], + (u16)(BytesToWrite-uHeaderLen), + pTX_Buffer->fifo_head.wFIFOCtl); status = PIPEnsSendBulkOut(pDevice,pContext); @@ -2719,7 +2628,10 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen, pContext->Type = CONTEXT_DATA_PACKET; pContext->uBufLen = (u16)BytesToWrite + 4 ; //USB header - s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pContext->sEthHeader.h_dest[0]), (u16) (BytesToWrite-uHeaderLen), pTX_Buffer->wFIFOCtl); + s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F), + &pContext->sEthHeader.h_dest[0], + (u16)(BytesToWrite - uHeaderLen), + pTX_Buffer->fifo_head.wFIFOCtl); status = PIPEnsSendBulkOut(pDevice,pContext); diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h index 4bbee1c2fcac..eecbe890027e 100644 --- a/drivers/staging/vt6656/rxtx.h +++ b/drivers/staging/vt6656/rxtx.h @@ -117,6 +117,7 @@ struct vnt_rts_g { u16 wDuration_bb; u16 wReserved; struct ieee80211_rts data; + struct vnt_tx_datahead_g data_head; } __packed; struct vnt_rts_g_fb { @@ -131,6 +132,7 @@ struct vnt_rts_g_fb { u16 wRTSDuration_ba_f1; u16 wRTSDuration_aa_f1; struct ieee80211_rts data; + struct vnt_tx_datahead_g_fb data_head; } __packed; struct vnt_rts_ab { @@ -138,6 +140,7 @@ struct vnt_rts_ab { u16 wDuration; u16 wReserved; struct ieee80211_rts data; + struct vnt_tx_datahead_ab data_head; } __packed; struct vnt_rts_a_fb { @@ -147,6 +150,7 @@ struct vnt_rts_a_fb { u16 wRTSDuration_f0; u16 wRTSDuration_f1; struct ieee80211_rts data; + struct vnt_tx_datahead_a_fb data_head; } __packed; /* CTS buffer header */ @@ -156,6 +160,7 @@ struct vnt_cts { u16 wReserved; struct ieee80211_cts data; u16 reserved2; + struct vnt_tx_datahead_g data_head; } __packed; struct vnt_cts_fb { @@ -166,6 +171,7 @@ struct vnt_cts_fb { u16 wCTSDuration_ba_f1; struct ieee80211_cts data; u16 reserved2; + struct vnt_tx_datahead_g_fb data_head; } __packed; union vnt_tx_data_head { @@ -178,12 +184,37 @@ union vnt_tx_data_head { /* cts g */ struct vnt_cts cts_g; struct vnt_cts_fb cts_g_fb; + /* no rts/cts */ + struct vnt_tx_datahead_a_fb data_head_a_fb; + struct vnt_tx_datahead_ab data_head_ab; }; -struct vnt_tx_buffer { - u8 byType; - u8 byPKTNO; - u16 wTxByteCount; +struct vnt_tx_mic_hdr { + struct vnt_mic_hdr hdr; + union vnt_tx_data_head head; +} __packed; + +union vnt_tx { + struct vnt_tx_mic_hdr mic; + union vnt_tx_data_head head; +}; + +union vnt_tx_head { + struct { + struct vnt_rrv_time_rts rts; + union vnt_tx tx; + } __packed tx_rts; + struct { + struct vnt_rrv_time_cts cts; + union vnt_tx tx; + } __packed tx_cts; + struct { + struct vnt_rrv_time_ab ab; + union vnt_tx tx; + } __packed tx_ab; +}; + +struct vnt_tx_fifo_head { u32 adwTxKey[4]; u16 wFIFOCtl; u16 wTimeStamp; @@ -191,6 +222,14 @@ struct vnt_tx_buffer { u16 wReserved; } __packed; +struct vnt_tx_buffer { + u8 byType; + u8 byPKTNO; + u16 wTxByteCount; + struct vnt_tx_fifo_head fifo_head; + union vnt_tx_head tx_head; +} __packed; + struct vnt_beacon_buffer { u8 byType; u8 byPKTNO; diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c index 3a03f1d5b685..5fc18ad822d3 100644 --- a/drivers/staging/vt6656/usbpipe.c +++ b/drivers/staging/vt6656/usbpipe.c @@ -118,6 +118,9 @@ int PIPEnsControlOut(struct vnt_private *pDevice, u8 byRequest, u16 wValue, if (pDevice->Flags & fMP_CONTROL_READS) return STATUS_FAILURE; + if (pDevice->pControlURB->hcpriv) + return STATUS_FAILURE; + MP_SET_FLAG(pDevice, fMP_CONTROL_WRITES); pDevice->sUsbCtlRequest.bRequestType = 0x40; @@ -177,6 +180,9 @@ int PIPEnsControlIn(struct vnt_private *pDevice, u8 byRequest, u16 wValue, if (pDevice->Flags & fMP_CONTROL_WRITES) return STATUS_FAILURE; + if (pDevice->pControlURB->hcpriv) + return STATUS_FAILURE; + MP_SET_FLAG(pDevice, fMP_CONTROL_READS); pDevice->sUsbCtlRequest.bRequestType = 0xC0; @@ -656,8 +662,6 @@ static void s_nsBulkOutIoCompleteWrite(struct urb *urb) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Write %d bytes\n",(int)ulBufLen); pDevice->ulBulkOutBytesWrite += ulBufLen; pDevice->ulBulkOutContCRCError = 0; - pDevice->nTxDataTimeCout = 0; - } else { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK Out failed %d\n", status); pDevice->ulBulkOutError++; diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c index 0013cb73d83b..2f8e2a875331 100644 --- a/drivers/staging/vt6656/wcmd.c +++ b/drivers/staging/vt6656/wcmd.c @@ -268,20 +268,14 @@ struct vnt_tx_mgmt *s_MgrMakeProbeRequest(struct vnt_private *pDevice, void vCommandTimerWait(struct vnt_private *pDevice, unsigned long MSecond) { - - init_timer(&pDevice->sTimerCommand); - - pDevice->sTimerCommand.data = (unsigned long)pDevice; - pDevice->sTimerCommand.function = (TimerFunction)vRunCommand; - pDevice->sTimerCommand.expires = RUN_AT((MSecond * HZ) / 1000); - - add_timer(&pDevice->sTimerCommand); - - return; + schedule_delayed_work(&pDevice->run_command_work, + msecs_to_jiffies(MSecond)); } -void vRunCommand(struct vnt_private *pDevice) +void vRunCommand(struct work_struct *work) { + struct vnt_private *pDevice = + container_of(work, struct vnt_private, run_command_work.work); struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; PWLAN_IE_SSID pItemSSID; PWLAN_IE_SSID pItemSSIDCurr; @@ -292,6 +286,9 @@ void vRunCommand(struct vnt_private *pDevice) u8 byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; u8 byData; + if (pDevice->Flags & fMP_DISCONNECTED) + return; + if (pDevice->dwDiagRefCount != 0) return; if (pDevice->bCmdRunning != true) @@ -660,22 +657,6 @@ void vRunCommand(struct vnt_private *pDevice) netif_wake_queue(pDevice->dev); } - if(pDevice->IsTxDataTrigger != false) { //TxDataTimer is not triggered at the first time - // printk("Re-initial TxDataTimer****\n"); - del_timer(&pDevice->sTimerTxData); - init_timer(&pDevice->sTimerTxData); - pDevice->sTimerTxData.data = (unsigned long) pDevice; - pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData; - pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback - pDevice->fTxDataInSleep = false; - pDevice->nTxDataTimeCout = 0; - } - else { - // printk("mike:-->First time trigger TimerTxData InSleep\n"); - } - pDevice->IsTxDataTrigger = true; - add_timer(&pDevice->sTimerTxData); - } else if(pMgmt->eCurrState < WMAC_STATE_ASSOCPENDING) { printk("WLAN_ASSOCIATE_WAIT:Association Fail???\n"); @@ -687,7 +668,6 @@ void vRunCommand(struct vnt_private *pDevice) vCommandTimerWait((void *) pDevice, ASSOCIATE_TIMEOUT/2); return; } - pDevice->byLinkWaitCount = 0; s_bCommandComplete(pDevice); break; @@ -696,7 +676,7 @@ void vRunCommand(struct vnt_private *pDevice) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_CMD_AP_MODE_START\n"); if (pMgmt->eConfigMode == WMAC_CONFIG_AP) { - del_timer(&pMgmt->sTimerSecondCallback); + cancel_delayed_work_sync(&pDevice->second_callback_work); pMgmt->eCurrState = WMAC_STATE_IDLE; pMgmt->eCurrMode = WMAC_MODE_STANDBY; pDevice->bLinkPass = false; @@ -724,7 +704,7 @@ void vRunCommand(struct vnt_private *pDevice) } pDevice->bLinkPass = true; ControlvMaskByte(pDevice,MESSAGE_REQUEST_MACREG,MAC_REG_PAPEDELAY,LEDSTS_STS,LEDSTS_INTER); - add_timer(&pMgmt->sTimerSecondCallback); + schedule_delayed_work(&pDevice->second_callback_work, HZ); } s_bCommandComplete(pDevice); break; @@ -1156,14 +1136,8 @@ static int s_bClearBSSID_SCAN(struct vnt_private *pDevice) //mike add:reset command timer void vResetCommandTimer(struct vnt_private *pDevice) { + cancel_delayed_work_sync(&pDevice->run_command_work); - //delete timer - del_timer(&pDevice->sTimerCommand); - //init timer - init_timer(&pDevice->sTimerCommand); - pDevice->sTimerCommand.data = (unsigned long)pDevice; - pDevice->sTimerCommand.function = (TimerFunction)vRunCommand; - pDevice->sTimerCommand.expires = RUN_AT(HZ); pDevice->cbFreeCmdQueue = CMD_Q_SIZE; pDevice->uCmdDequeueIdx = 0; pDevice->uCmdEnqueueIdx = 0; @@ -1171,33 +1145,3 @@ void vResetCommandTimer(struct vnt_private *pDevice) pDevice->bCmdRunning = false; pDevice->bCmdClear = false; } - -void BSSvSecondTxData(struct vnt_private *pDevice) -{ - struct vnt_manager *pMgmt = &pDevice->vnt_mgmt; - - pDevice->nTxDataTimeCout++; - - if (pDevice->nTxDataTimeCout < 4) { //don't tx data if timer less than 40s - // printk("mike:%s-->no data Tx not exceed the desired Time as %d\n",__FUNCTION__, - // (int)pDevice->nTxDataTimeCout); - pDevice->sTimerTxData.expires = RUN_AT(10 * HZ); //10s callback - add_timer(&pDevice->sTimerTxData); - return; - } - - spin_lock_irq(&pDevice->lock); - //is wap_supplicant running successful OR only open && sharekey mode! - if (((pDevice->bLinkPass == true) && - (pMgmt->eAuthenMode < WMAC_AUTH_WPA)) || //open && sharekey linking - (pDevice->fWPA_Authened == true)) { //wpa linking - // printk("mike:%s-->InSleep Tx Data Procedure\n",__FUNCTION__); - pDevice->fTxDataInSleep = true; - PSbSendNullPacket(pDevice); //send null packet - pDevice->fTxDataInSleep = false; - } - spin_unlock_irq(&pDevice->lock); - - pDevice->sTimerTxData.expires = RUN_AT(10 * HZ); //10s callback - add_timer(&pDevice->sTimerTxData); -} diff --git a/drivers/staging/vt6656/wcmd.h b/drivers/staging/vt6656/wcmd.h index db8b4cf7fd60..caf2684ce915 100644 --- a/drivers/staging/vt6656/wcmd.h +++ b/drivers/staging/vt6656/wcmd.h @@ -105,15 +105,6 @@ void vResetCommandTimer(struct vnt_private *); int bScheduleCommand(struct vnt_private *, CMD_CODE eCommand, u8 *pbyItem0); -void vRunCommand(struct vnt_private *); - -/* -void -WCMDvCommandThread( - void * Context - ); -*/ - -void BSSvSecondTxData(struct vnt_private *); +void vRunCommand(struct work_struct *work); #endif /* __WCMD_H__ */ diff --git a/drivers/staging/vt6656/wctl.c b/drivers/staging/vt6656/wctl.c index 47a655db51ef..814342cd948e 100644 --- a/drivers/staging/vt6656/wctl.c +++ b/drivers/staging/vt6656/wctl.c @@ -69,8 +69,7 @@ bool WCTLbIsDuplicate (PSCache pCache, struct ieee80211_hdr *pMACHeader) for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) { pCacheEntry = &(pCache->asCacheEntry[uIndex]); if ((pCacheEntry->wFmSequence == pMACHeader->seq_ctrl) && - (!compare_ether_addr(&(pCacheEntry->abyAddr2[0]), - &(pMACHeader->addr2[0]))) && + ether_addr_equal(pCacheEntry->abyAddr2, pMACHeader->addr2) && (LOBYTE(pCacheEntry->wFrameCtl) == LOBYTE(pMACHeader->frame_control)) ) { /* Duplicate match */ @@ -110,8 +109,8 @@ unsigned int WCTLuSearchDFCB(struct vnt_private *pDevice, for (ii = 0; ii < pDevice->cbDFCB; ii++) { if ((pDevice->sRxDFCB[ii].bInUse == true) && - (!compare_ether_addr(&(pDevice->sRxDFCB[ii].abyAddr2[0]), - &(pMACHeader->addr2[0])))) { + ether_addr_equal(pDevice->sRxDFCB[ii].abyAddr2, + pMACHeader->addr2)) { return ii; } } diff --git a/drivers/staging/vt6656/wmgr.c b/drivers/staging/vt6656/wmgr.c index b6cbd138a2b4..e26c41519b15 100644 --- a/drivers/staging/vt6656/wmgr.c +++ b/drivers/staging/vt6656/wmgr.c @@ -81,7 +81,7 @@ #include "control.h" #include "rndis.h" -static int msglevel =MSG_LEVEL_INFO; +static int msglevel = MSG_LEVEL_INFO; //static int msglevel =MSG_LEVEL_DEBUG; static int ChannelExceedZoneType(struct vnt_private *, u8 byCurrChannel); @@ -213,24 +213,6 @@ void vMgrObjectInit(struct vnt_private *pDevice) pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI; BSSvClearBSSList((void *) pDevice, false); - init_timer(&pMgmt->sTimerSecondCallback); - pMgmt->sTimerSecondCallback.data = (unsigned long)pDevice; - pMgmt->sTimerSecondCallback.function = (TimerFunction)BSSvSecondCallBack; - pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ); - - init_timer(&pDevice->sTimerCommand); - pDevice->sTimerCommand.data = (unsigned long)pDevice; - pDevice->sTimerCommand.function = (TimerFunction)vRunCommand; - pDevice->sTimerCommand.expires = RUN_AT(HZ); - - init_timer(&pDevice->sTimerTxData); - pDevice->sTimerTxData.data = (unsigned long)pDevice; - pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData; - pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback - pDevice->fTxDataInSleep = false; - pDevice->IsTxDataTrigger = false; - pDevice->nTxDataTimeCout = 0; - pDevice->cbFreeCmdQueue = CMD_Q_SIZE; pDevice->uCmdDequeueIdx = 0; pDevice->uCmdEnqueueIdx = 0; @@ -844,8 +826,8 @@ static void s_vMgrRxAssocResponse(struct vnt_private *pDevice, pDevice->bwextstep3 = false; pDevice->bWPASuppWextEnabled = false; -if(pMgmt->eCurrState == WMAC_STATE_ASSOC) - timer_expire(pDevice->sTimerCommand, 0); + if (pMgmt->eCurrState == WMAC_STATE_ASSOC) + schedule_delayed_work(&pDevice->run_command_work, 0); return; } @@ -1127,7 +1109,7 @@ static void s_vMgrRxAuthenSequence_2(struct vnt_private *pDevice, if ( cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS ){ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (OPEN) Successful.\n"); pMgmt->eCurrState = WMAC_STATE_AUTH; - timer_expire(pDevice->sTimerCommand, 0); + schedule_delayed_work(&pDevice->run_command_work, 0); } else { DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (OPEN) Failed.\n"); @@ -1302,7 +1284,7 @@ static void s_vMgrRxAuthenSequence_4(struct vnt_private *pDevice, if ( cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS ){ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (SHAREDKEY) Successful.\n"); pMgmt->eCurrState = WMAC_STATE_AUTH; - timer_expire(pDevice->sTimerCommand, 0); + schedule_delayed_work(&pDevice->run_command_work, 0); } else{ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (SHAREDKEY) Failed.\n"); @@ -1422,8 +1404,8 @@ static void s_vMgrRxDeauthentication(struct vnt_private *pDevice, pDevice->fWPA_Authened = false; DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP deauthed me, reason=%d.\n", cpu_to_le16((*(sFrame.pwReason)))); // TODO: update BSS list for specific BSSID if pre-authentication case - if (!compare_ether_addr(sFrame.pHdr->sA3.abyAddr3, - pMgmt->abyCurrBSSID)) { + if (ether_addr_equal(sFrame.pHdr->sA3.abyAddr3, + pMgmt->abyCurrBSSID)) { if (pMgmt->eCurrState >= WMAC_STATE_AUTHPENDING) { pMgmt->sNodeDBTable[0].bActive = false; pMgmt->eCurrMode = WMAC_MODE_STANDBY; @@ -3095,7 +3077,7 @@ struct vnt_tx_mgmt *s_MgrMakeProbeResponse(struct vnt_private *pDevice, * * * Return Value: - * A ptr to frame or NULL on allocation failue + * A ptr to frame or NULL on allocation failure * -*/ diff --git a/drivers/staging/vt6656/wmgr.h b/drivers/staging/vt6656/wmgr.h index 5424c7f820ad..26ba47da467b 100644 --- a/drivers/staging/vt6656/wmgr.h +++ b/drivers/staging/vt6656/wmgr.h @@ -310,9 +310,6 @@ struct vnt_manager { u8 byMgmtPacketPool[sizeof(struct vnt_tx_mgmt) + WLAN_A3FR_MAXLEN]; - /* One second callback timer */ - struct timer_list sTimerSecondCallback; - /* Temporarily Rx Mgmt Packet Descriptor */ struct vnt_rx_mgmt sRxPacket; diff --git a/drivers/staging/vt6656/wpactl.c b/drivers/staging/vt6656/wpactl.c index 9f1b413ce86f..003bd7c614e5 100644 --- a/drivers/staging/vt6656/wpactl.c +++ b/drivers/staging/vt6656/wpactl.c @@ -227,7 +227,7 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Set\n"); } else { // Key Table Full - if (!compare_ether_addr(¶m->addr[0], pDevice->abyBSSID)) { + if (ether_addr_equal(param->addr, pDevice->abyBSSID)) { //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n")); return -EINVAL; } else { diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c index 560c0ab617d1..b031ecd4f3c0 100644 --- a/drivers/staging/winbond/mto.c +++ b/drivers/staging/winbond/mto.c @@ -21,6 +21,7 @@ #include "wbhal.h" #include "wb35reg_f.h" #include "core.h" +#include "mto.h" /* Declare SQ3 to rate and fragmentation threshold table */ /* Declare fragmentation threshold table */ @@ -45,12 +46,6 @@ static int retryrate_rec[MTO_MAX_DATA_RATE_LEVELS]; static u8 boSparseTxTraffic; -void MTO_Init(struct wbsoft_priv *adapter); -void TxRateReductionCtrl(struct wbsoft_priv *adapter); -void MTO_SetTxCount(struct wbsoft_priv *adapter, u8 t0, u8 index); -void MTO_TxFailed(struct wbsoft_priv *adapter); -void hal_get_dto_para(struct wbsoft_priv *adapter, char *buffer); - /* * =========================================================================== * MTO_Init -- diff --git a/drivers/staging/winbond/mto.h b/drivers/staging/winbond/mto.h index a0f659cf99ff..8d41eeda45bf 100644 --- a/drivers/staging/winbond/mto.h +++ b/drivers/staging/winbond/mto.h @@ -127,12 +127,8 @@ extern u16 MTO_Frag_Th_Tbl[]; #define MTO_DATA_RATE() MTO_Data_Rate_Tbl[MTO_RATE_LEVEL()] #define MTO_FRAG_TH() MTO_Frag_Th_Tbl[MTO_FRAG_TH_LEVEL()] -extern void MTO_Init(struct wbsoft_priv *); -extern void MTO_PeriodicTimerExpired(struct wbsoft_priv *); -extern void MTO_SetDTORateRange(struct wbsoft_priv *, u8 *, u8); -extern u8 MTO_GetTxRate(struct wbsoft_priv *adapter, u32 fpdu_len); -extern u8 MTO_GetTxFallbackRate(struct wbsoft_priv *adapter); -extern void MTO_SetTxCount(struct wbsoft_priv *adapter, u8 t0, u8 index); +void MTO_Init(struct wbsoft_priv *); +void MTO_SetTxCount(struct wbsoft_priv *adapter, u8 t0, u8 index); #endif /* __MTO_H__ */ diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c index cfbfbbb53866..d970660f6523 100644 --- a/drivers/staging/winbond/phy_calibration.c +++ b/drivers/staging/winbond/phy_calibration.c @@ -27,10 +27,12 @@ #define DEG2RAD(X) (0.017453 * (X)) static const s32 Angles[] = { - FIXED(DEG2RAD(45.0)), FIXED(DEG2RAD(26.565)), FIXED(DEG2RAD(14.0362)), - FIXED(DEG2RAD(7.12502)), FIXED(DEG2RAD(3.57633)), FIXED(DEG2RAD(1.78991)), - FIXED(DEG2RAD(0.895174)), FIXED(DEG2RAD(0.447614)), FIXED(DEG2RAD(0.223811)), - FIXED(DEG2RAD(0.111906)), FIXED(DEG2RAD(0.055953)), FIXED(DEG2RAD(0.027977)) + FIXED(DEG2RAD(45.0)), FIXED(DEG2RAD(26.565)), + FIXED(DEG2RAD(14.0362)), FIXED(DEG2RAD(7.12502)), + FIXED(DEG2RAD(3.57633)), FIXED(DEG2RAD(1.78991)), + FIXED(DEG2RAD(0.895174)), FIXED(DEG2RAD(0.447614)), + FIXED(DEG2RAD(0.223811)), FIXED(DEG2RAD(0.111906)), + FIXED(DEG2RAD(0.055953)), FIXED(DEG2RAD(0.027977)) }; /****************** LOCAL FUNCTION DECLARATION SECTION **********************/ @@ -296,7 +298,8 @@ void _sin_cos(s32 angle, s32 *sin, s32 *cos) } } -static unsigned char hal_get_dxx_reg(struct hw_data *pHwData, u16 number, u32 *pValue) +static unsigned char hal_get_dxx_reg(struct hw_data *pHwData, u16 number, + u32 *pValue) { if (number < 0x1000) number += 0x1000; @@ -304,7 +307,8 @@ static unsigned char hal_get_dxx_reg(struct hw_data *pHwData, u16 number, u32 *p } #define hw_get_dxx_reg(_A, _B, _C) hal_get_dxx_reg(_A, _B, (u32 *)_C) -static unsigned char hal_set_dxx_reg(struct hw_data *pHwData, u16 number, u32 value) +static unsigned char hal_set_dxx_reg(struct hw_data *pHwData, u16 number, + u32 value) { unsigned char ret; @@ -407,7 +411,8 @@ void _rxadc_dc_offset_cancellation_winbond(struct hw_data *phw_data, u32 frequen PHY_DEBUG(("[CAL] ** adc_dc_cal_i = %d (0x%04X)\n", _s9_to_s32(val&0x000001FF), val&0x000001FF)); PHY_DEBUG(("[CAL] ** adc_dc_cal_q = %d (0x%04X)\n", - _s9_to_s32((val&0x0003FE00)>>9), (val&0x0003FE00)>>9)); + _s9_to_s32((val&0x0003FE00)>>9), + (val&0x0003FE00)>>9)); #endif hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val); @@ -535,7 +540,8 @@ void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data) } PHY_DEBUG(("[CAL] ** fix_cancel_dc_i = %d (0x%04X)\n", - fix_cancel_dc_i, _s32_to_s5(fix_cancel_dc_i))); + fix_cancel_dc_i, + _s32_to_s5(fix_cancel_dc_i))); if ((abs(mag_1-mag_0)*6) > mag_0) break; @@ -711,7 +717,8 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data, loop = LOOP_TIMES; while (loop > 0) { - PHY_DEBUG(("[CAL] [%d.] <_tx_iq_calibration_loop>\n", (LOOP_TIMES-loop+1))); + PHY_DEBUG(("[CAL] [%d.] <_tx_iq_calibration_loop>\n", + (LOOP_TIMES-loop+1))); iqcal_tone_i_avg = 0; iqcal_tone_q_avg = 0; @@ -719,8 +726,8 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data, return 0; for (capture_time = 0; capture_time < 10; capture_time++) { /* - * a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to - * enable "IQ calibration Mode II" + * a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" + * to 0x1 to enable "IQ calibration Mode II" */ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE); reg_mode_ctrl &= ~MASK_IQCAL_MODE; @@ -749,8 +756,8 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data, PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); /* - * d. Set iqcal_mode[1:0] to 0x3 and set "calib_start" to 0x1 to - * enable "IQ calibration Mode II" + * d. Set iqcal_mode[1:0] to 0x3 and set "calib_start" + * to 0x1 to enable "IQ calibration Mode II" */ /* hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val); */ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); @@ -766,7 +773,7 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data, iqcal_tone_i = _s13_to_s32(val & 0x00001FFF); iqcal_tone_q = _s13_to_s32((val & 0x03FFE000) >> 13); PHY_DEBUG(("[CAL] ** iqcal_tone_i = %d, iqcal_tone_q = %d\n", - iqcal_tone_i, iqcal_tone_q)); + iqcal_tone_i, iqcal_tone_q)); if (capture_time == 0) continue; else { @@ -1146,7 +1153,8 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre /* for (loop = 0; loop < LOOP_TIMES; loop++) */ loop = LOOP_TIMES; while (loop > 0) { - PHY_DEBUG(("[CAL] [%d.] <_rx_iq_calibration_loop>\n", (LOOP_TIMES-loop+1))); + PHY_DEBUG(("[CAL] [%d.] <_rx_iq_calibration_loop>\n", + (LOOP_TIMES-loop+1))); iqcal_tone_i_avg = 0; iqcal_tone_q_avg = 0; iqcal_image_i_avg = 0; @@ -1199,13 +1207,13 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre /* d. */ rot_tone_i_b = (iqcal_tone_i * iqcal_tone_i + - iqcal_tone_q * iqcal_tone_q) / 1024; + iqcal_tone_q * iqcal_tone_q) / 1024; rot_tone_q_b = (iqcal_tone_i * iqcal_tone_q * (-1) + - iqcal_tone_q * iqcal_tone_i) / 1024; + iqcal_tone_q * iqcal_tone_i) / 1024; rot_image_i_b = (iqcal_image_i * iqcal_tone_i - - iqcal_image_q * iqcal_tone_q) / 1024; + iqcal_image_q * iqcal_tone_q) / 1024; rot_image_q_b = (iqcal_image_i * iqcal_tone_q + - iqcal_image_q * iqcal_tone_i) / 1024; + iqcal_image_q * iqcal_tone_i) / 1024; PHY_DEBUG(("[CAL] ** rot_tone_i_b = %d\n", rot_tone_i_b)); PHY_DEBUG(("[CAL] ** rot_tone_q_b = %d\n", rot_tone_q_b)); @@ -1225,8 +1233,10 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre b_2 = (rot_image_q_b * 32768) / rot_tone_i_b - phw_data->iq_rsdl_phase_tx_d2; - PHY_DEBUG(("[CAL] ** iq_rsdl_gain_tx_d2 = %d\n", phw_data->iq_rsdl_gain_tx_d2)); - PHY_DEBUG(("[CAL] ** iq_rsdl_phase_tx_d2= %d\n", phw_data->iq_rsdl_phase_tx_d2)); + PHY_DEBUG(("[CAL] ** iq_rsdl_gain_tx_d2 = %d\n", + phw_data->iq_rsdl_gain_tx_d2)); + PHY_DEBUG(("[CAL] ** iq_rsdl_phase_tx_d2= %d\n", + phw_data->iq_rsdl_phase_tx_d2)); PHY_DEBUG(("[CAL] ***** EPSILON/2 = %d\n", a_2)); PHY_DEBUG(("[CAL] ***** THETA/2 = %d\n", b_2)); @@ -1272,7 +1282,8 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre /* e. */ pwr_tone = (iqcal_tone_i*iqcal_tone_i + iqcal_tone_q*iqcal_tone_q); - pwr_image = (iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q)*factor; + pwr_image = (iqcal_image_i*iqcal_image_i + + iqcal_image_q*iqcal_image_q)*factor; PHY_DEBUG(("[CAL] ** pwr_tone = %d\n", pwr_tone)); PHY_DEBUG(("[CAL] ** pwr_image = %d\n", pwr_image)); @@ -1569,7 +1580,8 @@ unsigned char adjust_TXVGA_for_iq_mag(struct hw_data *phw_data) sqsum = iqcal_tone_i0*iqcal_tone_i0 + iqcal_tone_q0*iqcal_tone_q0; iq_mag_0_tx = (s32) _sqrt(sqsum); - PHY_DEBUG(("[CAL] ** auto_adjust_txvga_for_iq_mag_0_tx=%d\n", iq_mag_0_tx)); + PHY_DEBUG(("[CAL] ** auto_adjust_txvga_for_iq_mag_0_tx=%d\n", + iq_mag_0_tx)); if (iq_mag_0_tx >= 700 && iq_mag_0_tx <= 1750) break; diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c index 75b775252af1..80b4b343a94e 100644 --- a/drivers/staging/winbond/reg.c +++ b/drivers/staging/winbond/reg.c @@ -920,7 +920,7 @@ void Uxx_power_on_procedure(struct hw_data *pHwData) Wb35Reg_WriteSync(pHwData, 0x03f8, 0x7ff); } -static void Set_ChanIndep_RfData_al7230_24(struct hw_data *pHwData, u32 *pltmp, +static void Set_ChanIndep_RfData_al7230_24(struct hw_data *pHwData, u32 *pltmp, char number) { u8 i; @@ -930,7 +930,7 @@ static void Set_ChanIndep_RfData_al7230_24(struct hw_data *pHwData, u32 *pltmp, } } -static void Set_ChanIndep_RfData_al7230_50(struct hw_data *pHwData, u32 *pltmp, +static void Set_ChanIndep_RfData_al7230_50(struct hw_data *pHwData, u32 *pltmp, char number) { u8 i; @@ -1088,7 +1088,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData) msleep(5); ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse((0x0F << 20) | 0xF01A0, 20); - Wb35Reg_WriteSync(pHwData, 0x0864, ltmp) ; + Wb35Reg_WriteSync(pHwData, 0x0864, ltmp); Wb35Reg_WriteSync(pHwData, 0x105c, pHwData->reg.BB5C); pHwData->reg.BB50 &= ~0x13; /* (MASK_IQCAL_MODE|MASK_CALIB_START); */ @@ -1620,13 +1620,13 @@ void BBProcessor_initial(struct hw_data *pHwData) reg->SQ3_filter[i] = 0x2f; /* half of Bit 0 ~ 6 */ } -static inline void set_tx_power_per_channel_max2829(struct hw_data *pHwData, +static inline void set_tx_power_per_channel_max2829(struct hw_data *pHwData, struct chan_info Channel) { RFSynthesizer_SetPowerIndex(pHwData, 100); } -static void set_tx_power_per_channel_al2230(struct hw_data *pHwData, +static void set_tx_power_per_channel_al2230(struct hw_data *pHwData, struct chan_info Channel) { u8 index = 100; @@ -1636,7 +1636,7 @@ static void set_tx_power_per_channel_al2230(struct hw_data *pHwData, RFSynthesizer_SetPowerIndex(pHwData, index); } -static void set_tx_power_per_channel_al7230(struct hw_data *pHwData, +static void set_tx_power_per_channel_al7230(struct hw_data *pHwData, struct chan_info Channel) { u8 i, index = 100; @@ -1660,7 +1660,7 @@ static void set_tx_power_per_channel_al7230(struct hw_data *pHwData, RFSynthesizer_SetPowerIndex(pHwData, index); } -static void set_tx_power_per_channel_wb242(struct hw_data *pHwData, +static void set_tx_power_per_channel_wb242(struct hw_data *pHwData, struct chan_info Channel) { u8 index = 100; @@ -2096,7 +2096,7 @@ void Mxx_initial(struct hw_data *pHwData) pltmp[5] = reg->M38_MacControl; /* M3C */ - tmp = (DEFAULT_PIFST << 26) | (DEFAULT_EIFST << 16) | (DEFAULT_DIFST << 8) | (DEFAULT_SIFST << 4) | DEFAULT_OSIFST ; + tmp = (DEFAULT_PIFST << 26) | (DEFAULT_EIFST << 16) | (DEFAULT_DIFST << 8) | (DEFAULT_SIFST << 4) | DEFAULT_OSIFST; reg->M3C_MacControl = tmp; pltmp[6] = tmp; diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c index 30a77ccfe480..708c5b05f86c 100644 --- a/drivers/staging/winbond/wb35tx.c +++ b/drivers/staging/winbond/wb35tx.c @@ -180,7 +180,7 @@ void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount) { struct hw_data *pHwData = &adapter->sHwData; struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; - unsigned char Trigger = false; + bool Trigger = false; if (pWb35Tx->TxTimer > TimeCount) Trigger = true; diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index f1bce18ea828..a4fd5c4717a8 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -98,10 +98,10 @@ static int prism2_domibset_pstr32(wlandevice_t *wlandev, /* The interface functions, called by the cfg80211 layer */ -int prism2_change_virtual_intf(struct wiphy *wiphy, - struct net_device *dev, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) +static int prism2_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) { wlandevice_t *wlandev = dev->ml_priv; u32 data; @@ -122,7 +122,7 @@ int prism2_change_virtual_intf(struct wiphy *wiphy, data = 1; break; default: - printk(KERN_WARNING "Operation mode: %d not support\n", type); + netdev_warn(dev, "Operation mode: %d not support\n", type); return -EOPNOTSUPP; } @@ -140,9 +140,9 @@ exit: return err; } -int prism2_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_index, bool pairwise, const u8 *mac_addr, - struct key_params *params) +static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) { wlandevice_t *wlandev = dev->ml_priv; u32 did; @@ -199,9 +199,10 @@ exit: return err; } -int prism2_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie, - void (*callback)(void *cookie, struct key_params*)) +static int prism2_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params*)) { wlandevice_t *wlandev = dev->ml_priv; struct key_params params; @@ -228,8 +229,8 @@ int prism2_get_key(struct wiphy *wiphy, struct net_device *dev, return 0; } -int prism2_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_index, bool pairwise, const u8 *mac_addr) +static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool pairwise, const u8 *mac_addr) { wlandevice_t *wlandev = dev->ml_priv; u32 did; @@ -274,8 +275,8 @@ exit: return err; } -int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_index, bool unicast, bool multicast) +static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool unicast, bool multicast) { wlandevice_t *wlandev = dev->ml_priv; @@ -293,8 +294,8 @@ int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, } -int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac, struct station_info *sinfo) +static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) { wlandevice_t *wlandev = dev->ml_priv; struct p80211msg_lnxreq_commsquality quality; @@ -327,7 +328,7 @@ int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, return result; } -int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +static int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct net_device *dev; struct prism2_wiphy_private *priv = wiphy_priv(wiphy); @@ -352,7 +353,7 @@ int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) return -EBUSY; if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { - printk(KERN_ERR "Can't scan in AP mode\n"); + netdev_err(dev, "Can't scan in AP mode\n"); return -EOPNOTSUPP; } @@ -436,7 +437,7 @@ exit: return err; } -int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed) +static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct prism2_wiphy_private *priv = wiphy_priv(wiphy); wlandevice_t *wlandev = priv->wlandev; @@ -478,8 +479,8 @@ exit: return err; } -int prism2_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme) +static int prism2_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) { wlandevice_t *wlandev = dev->ml_priv; struct ieee80211_channel *channel = sme->channel; @@ -510,7 +511,7 @@ int prism2_connect(struct wiphy *wiphy, struct net_device *dev, ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep)) msg_join.authtype.data = P80211ENUM_authalg_sharedkey; else - printk(KERN_WARNING + netdev_warn(dev, "Unhandled authorisation type for connect (%d)\n", sme->auth_type); @@ -602,8 +603,8 @@ exit: return err; } -int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) +static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) { wlandevice_t *wlandev = dev->ml_priv; struct p80211msg_lnxreq_autojoin msg_join; @@ -626,20 +627,20 @@ int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev, } -int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params) +static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) { return -EOPNOTSUPP; } -int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) { return -EOPNOTSUPP; } -int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, int mbm) +static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) { struct prism2_wiphy_private *priv = wiphy_priv(wiphy); wlandevice_t *wlandev = priv->wlandev; @@ -665,8 +666,8 @@ exit: return err; } -int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - int *dbm) +static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + int *dbm) { struct prism2_wiphy_private *priv = wiphy_priv(wiphy); wlandevice_t *wlandev = priv->wlandev; diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c index c1a8cb625154..5b8b094c8726 100644 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ b/drivers/staging/wlan-ng/hfa384x_usb.c @@ -355,7 +355,7 @@ static int submit_rx_urb(hfa384x_t *hw, gfp_t memflags) /* Check whether we need to reset the RX pipe */ if (result == -EPIPE) { - printk(KERN_WARNING + netdev_warn(hw->wlandev->netdev, "%s rx pipe stalled: requesting reset\n", hw->wlandev->netdev->name); if (!test_and_set_bit(WORK_RX_HALT, &hw->usb_flags)) @@ -405,7 +405,7 @@ static int submit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, gfp_t memflags) /* Test whether we need to reset the TX pipe */ if (result == -EPIPE) { - printk(KERN_WARNING + netdev_warn(hw->wlandev->netdev, "%s tx pipe stalled: requesting reset\n", netdev->name); set_bit(WORK_TX_HALT, &hw->usb_flags); @@ -454,11 +454,11 @@ static void hfa384x_usb_defer(struct work_struct *data) ret = usb_clear_halt(hw->usb, hw->endp_in); if (ret != 0) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "Failed to clear rx pipe for %s: err=%d\n", netdev->name, ret); } else { - printk(KERN_INFO "%s rx pipe reset complete.\n", + netdev_info(hw->wlandev->netdev, "%s rx pipe reset complete.\n", netdev->name); clear_bit(WORK_RX_HALT, &hw->usb_flags); set_bit(WORK_RX_RESUME, &hw->usb_flags); @@ -471,7 +471,7 @@ static void hfa384x_usb_defer(struct work_struct *data) ret = submit_rx_urb(hw, GFP_KERNEL); if (ret != 0) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "Failed to resume %s rx pipe.\n", netdev->name); } else { clear_bit(WORK_RX_RESUME, &hw->usb_flags); @@ -485,11 +485,11 @@ static void hfa384x_usb_defer(struct work_struct *data) usb_kill_urb(&hw->tx_urb); ret = usb_clear_halt(hw->usb, hw->endp_out); if (ret != 0) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "Failed to clear tx pipe for %s: err=%d\n", netdev->name, ret); } else { - printk(KERN_INFO "%s tx pipe reset complete.\n", + netdev_info(hw->wlandev->netdev, "%s tx pipe reset complete.\n", netdev->name); clear_bit(WORK_TX_HALT, &hw->usb_flags); set_bit(WORK_TX_RESUME, &hw->usb_flags); @@ -1211,7 +1211,7 @@ int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis) result = usb_reset_device(hw->usb); if (result < 0) { - printk(KERN_ERR "usb_reset_device() failed, result=%d.\n", + netdev_err(hw->wlandev->netdev, "usb_reset_device() failed, result=%d.\n", result); } @@ -1311,7 +1311,7 @@ cleanup: if (ctlx->state == CTLX_COMPLETE) { result = completor->complete(completor); } else { - printk(KERN_WARNING "CTLX[%d] error: state(%s)\n", + netdev_warn(hw->wlandev->netdev, "CTLX[%d] error: state(%s)\n", le16_to_cpu(ctlx->outbuf.type), ctlxstr(ctlx->state)); result = -EIO; @@ -2018,7 +2018,7 @@ int hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) if (hw->dlstate != HFA384x_DLSTATE_FLASHENABLED) return -EINVAL; - printk(KERN_INFO "Download %d bytes to flash @0x%06x\n", len, daddr); + netdev_info(hw->wlandev->netdev, "Download %d bytes to flash @0x%06x\n", len, daddr); /* Convert to flat address for arithmetic */ /* NOTE: dlbuffer RID stores the address in AUX format */ @@ -2028,7 +2028,7 @@ int hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) hw->bufinfo.page, hw->bufinfo.offset, dlbufaddr); #if 0 - printk(KERN_WARNING "dlbuf@0x%06lx len=%d to=%d\n", dlbufaddr, + netdev_warn(hw->wlandev->netdev, "dlbuf@0x%06lx len=%d to=%d\n", dlbufaddr, hw->bufinfo.len, hw->dltimeout); #endif /* Calculations to determine how many fills of the dlbuffer to do @@ -2055,14 +2055,14 @@ int hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) burnlo = HFA384x_ADDR_CMD_MKOFF(burndaddr); burnhi = HFA384x_ADDR_CMD_MKPAGE(burndaddr); - printk(KERN_INFO "Writing %d bytes to flash @0x%06x\n", + netdev_info(hw->wlandev->netdev, "Writing %d bytes to flash @0x%06x\n", burnlen, burndaddr); /* Set the download mode */ result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_NV, burnlo, burnhi, burnlen); if (result) { - printk(KERN_ERR "download(NV,lo=%x,hi=%x,len=%x) " + netdev_err(hw->wlandev->netdev, "download(NV,lo=%x,hi=%x,len=%x) " "cmd failed, result=%d. Aborting d/l\n", burnlo, burnhi, burnlen, result); goto exit_proc; @@ -2094,7 +2094,7 @@ int hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) HFA384x_PROGMODE_NVWRITE, 0, 0, 0); if (result) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "download(NVWRITE,lo=%x,hi=%x,len=%x) " "cmd failed, result=%d. Aborting d/l\n", burnlo, burnhi, burnlen, result); @@ -2279,7 +2279,7 @@ int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr) /* Check that a port isn't active */ for (i = 0; i < HFA384x_PORTID_MAX; i++) { if (hw->port_enabled[i]) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "Can't download with a macport enabled.\n"); return -EINVAL; } @@ -2287,7 +2287,7 @@ int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr) /* Check that we're not already in a download state */ if (hw->dlstate != HFA384x_DLSTATE_DISABLED) { - printk(KERN_ERR "Download state not disabled.\n"); + netdev_err(hw->wlandev->netdev, "Download state not disabled.\n"); return -EINVAL; } @@ -2352,7 +2352,7 @@ int hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) if (hw->dlstate != HFA384x_DLSTATE_RAMENABLED) return -EINVAL; - printk(KERN_INFO "Writing %d bytes to ram @0x%06x\n", len, daddr); + netdev_info(hw->wlandev->netdev, "Writing %d bytes to ram @0x%06x\n", len, daddr); /* How many dowmem calls? */ nwrites = len / HFA384x_USB_RWMEM_MAXLEN; @@ -2449,7 +2449,7 @@ int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len) len); if (result) { - printk(KERN_WARNING + netdev_warn(hw->wlandev->netdev, "Read from index %zd failed, continuing\n", i); continue; } @@ -2462,13 +2462,13 @@ int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len) pdrcode = le16_to_cpu(pda[currpdr + 1]); /* Test the record length */ if (pdrlen > HFA384x_PDR_LEN_MAX || pdrlen == 0) { - printk(KERN_ERR "pdrlen invalid=%d\n", pdrlen); + netdev_err(hw->wlandev->netdev, "pdrlen invalid=%d\n", pdrlen); pdaok = 0; break; } /* Test the code */ if (!hfa384x_isgood_pdrcode(pdrcode)) { - printk(KERN_ERR "pdrcode invalid=%d\n", + netdev_err(hw->wlandev->netdev, "pdrcode invalid=%d\n", pdrcode); pdaok = 0; break; @@ -2484,7 +2484,7 @@ int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len) } } if (pdaok) { - printk(KERN_INFO + netdev_info(hw->wlandev->netdev, "PDA Read from 0x%08x in %s space.\n", pdaloc[i].cardaddr, pdaloc[i].auxctl == 0 ? "EXTDS" : @@ -2564,20 +2564,20 @@ int hfa384x_drvr_start(hfa384x_t *hw) result = usb_get_status(hw->usb, USB_RECIP_ENDPOINT, hw->endp_in, &status); if (result < 0) { - printk(KERN_ERR "Cannot get bulk in endpoint status.\n"); + netdev_err(hw->wlandev->netdev, "Cannot get bulk in endpoint status.\n"); goto done; } if ((status == 1) && usb_clear_halt(hw->usb, hw->endp_in)) - printk(KERN_ERR "Failed to reset bulk in endpoint.\n"); + netdev_err(hw->wlandev->netdev, "Failed to reset bulk in endpoint.\n"); result = usb_get_status(hw->usb, USB_RECIP_ENDPOINT, hw->endp_out, &status); if (result < 0) { - printk(KERN_ERR "Cannot get bulk out endpoint status.\n"); + netdev_err(hw->wlandev->netdev, "Cannot get bulk out endpoint status.\n"); goto done; } if ((status == 1) && usb_clear_halt(hw->usb, hw->endp_out)) - printk(KERN_ERR "Failed to reset bulk out endpoint.\n"); + netdev_err(hw->wlandev->netdev, "Failed to reset bulk out endpoint.\n"); /* Synchronous unlink, in case we're trying to restart the driver */ usb_kill_urb(&hw->rx_urb); @@ -2585,7 +2585,7 @@ int hfa384x_drvr_start(hfa384x_t *hw) /* Post the IN urb */ result = submit_rx_urb(hw, GFP_KERNEL); if (result != 0) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "Fatal, failed to submit RX URB, result=%d\n", result); goto done; } @@ -2605,7 +2605,7 @@ int hfa384x_drvr_start(hfa384x_t *hw) result = result2 = hfa384x_cmd_initialize(hw); if (result1 != 0) { if (result2 != 0) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "cmd_initialize() failed on two attempts, results %d and %d\n", result1, result2); usb_kill_urb(&hw->rx_urb); @@ -2616,9 +2616,9 @@ int hfa384x_drvr_start(hfa384x_t *hw) pr_debug("but second attempt succeeded. All should be ok\n"); } } else if (result2 != 0) { - printk(KERN_WARNING "First cmd_initialize() succeeded, but second attempt failed (result=%d)\n", + netdev_warn(hw->wlandev->netdev, "First cmd_initialize() succeeded, but second attempt failed (result=%d)\n", result2); - printk(KERN_WARNING + netdev_warn(hw->wlandev->netdev, "Most likely the card will be functional\n"); goto done; } @@ -2709,7 +2709,7 @@ int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, char *ptr; if (hw->tx_urb.status == -EINPROGRESS) { - printk(KERN_WARNING "TX URB already in use\n"); + netdev_warn(hw->wlandev->netdev, "TX URB already in use\n"); result = 3; goto exit; } @@ -2784,7 +2784,7 @@ int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, result = 1; ret = submit_tx_urb(hw, &hw->tx_urb, GFP_ATOMIC); if (ret != 0) { - printk(KERN_ERR "submit_tx_urb() failed, error=%d\n", ret); + netdev_err(hw->wlandev->netdev, "submit_tx_urb() failed, error=%d\n", ret); result = 3; } @@ -3009,7 +3009,7 @@ static void unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) break; default: - printk(KERN_ERR "CTLX[%d] not in a terminating state(%s)\n", + netdev_err(hw->wlandev->netdev, "CTLX[%d] not in a terminating state(%s)\n", le16_to_cpu(ctlx->outbuf.type), ctlxstr(ctlx->state)); break; } /* switch */ @@ -3091,7 +3091,7 @@ static void hfa384x_usbctlxq_run(hfa384x_t *hw) * this CTLX back in the "pending" queue * and schedule a reset ... */ - printk(KERN_WARNING + netdev_warn(hw->wlandev->netdev, "%s tx pipe stalled: requesting reset\n", hw->wlandev->netdev->name); list_move(&head->list, &hw->ctlxq.pending); @@ -3101,12 +3101,12 @@ static void hfa384x_usbctlxq_run(hfa384x_t *hw) } if (result == -ESHUTDOWN) { - printk(KERN_WARNING "%s urb shutdown!\n", + netdev_warn(hw->wlandev->netdev, "%s urb shutdown!\n", hw->wlandev->netdev->name); break; } - printk(KERN_ERR "Failed to submit CTLX[%d]: error=%d\n", + netdev_err(hw->wlandev->netdev, "Failed to submit CTLX[%d]: error=%d\n", le16_to_cpu(head->outbuf.type), result); unlocked_usbctlx_complete(hw, head); } /* while */ @@ -3173,7 +3173,7 @@ static void hfa384x_usbin_callback(struct urb *urb) break; case -EPIPE: - printk(KERN_WARNING "%s rx pipe stalled: requesting reset\n", + netdev_warn(hw->wlandev->netdev, "%s rx pipe stalled: requesting reset\n", wlandev->netdev->name); if (!test_and_set_bit(WORK_RX_HALT, &hw->usb_flags)) schedule_work(&hw->usb_work); @@ -3224,7 +3224,7 @@ static void hfa384x_usbin_callback(struct urb *urb) result = submit_rx_urb(hw, GFP_ATOMIC); if (result != 0) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "Fatal, failed to resubmit rx_urb. error=%d\n", result); } @@ -3360,7 +3360,7 @@ retry: * Check that our message is what we're expecting ... */ if (ctlx->outbuf.type != intype) { - printk(KERN_WARNING + netdev_warn(hw->wlandev->netdev, "Expected IN[%d], received IN[%d] - ignored.\n", le16_to_cpu(ctlx->outbuf.type), le16_to_cpu(intype)); @@ -3396,7 +3396,7 @@ retry: /* * Throw this CTLX away ... */ - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "Matched IN URB, CTLX[%d] in invalid state(%s)." " Discarded.\n", le16_to_cpu(ctlx->outbuf.type), @@ -3534,7 +3534,7 @@ static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb) break; default: - printk(KERN_WARNING "Received frame on unsupported port=%d\n", + netdev_warn(hw->wlandev->netdev, "Received frame on unsupported port=%d\n", HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status)); goto done; break; @@ -3596,7 +3596,7 @@ static void hfa384x_int_rxmonitor(wlandevice_t *wlandev, skb = dev_alloc_skb(skblen); if (skb == NULL) { - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "alloc_skb failed trying to allocate %d bytes\n", skblen); return; @@ -3714,7 +3714,7 @@ static void hfa384x_usbout_callback(struct urb *urb) case -EPIPE: { hfa384x_t *hw = wlandev->priv; - printk(KERN_WARNING + netdev_warn(hw->wlandev->netdev, "%s tx pipe stalled: requesting reset\n", wlandev->netdev->name); if (!test_and_set_bit @@ -3747,7 +3747,7 @@ static void hfa384x_usbout_callback(struct urb *urb) break; default: - printk(KERN_INFO "unknown urb->status=%d\n", + netdev_info(wlandev->netdev, "unknown urb->status=%d\n", urb->status); ++(wlandev->linux_stats.tx_errors); break; @@ -3841,7 +3841,7 @@ retry: default: /* This is NOT a valid CTLX "success" state! */ - printk(KERN_ERR + netdev_err(hw->wlandev->netdev, "Illegal CTLX[%d] success state(%s, %d) in OUT URB\n", le16_to_cpu(ctlx->outbuf.type), ctlxstr(ctlx->state), urb->status); @@ -3851,7 +3851,7 @@ retry: /* If the pipe has stalled then we need to reset it */ if ((urb->status == -EPIPE) && !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags)) { - printk(KERN_WARNING + netdev_warn(hw->wlandev->netdev, "%s tx pipe stalled: requesting reset\n", hw->wlandev->netdev->name); schedule_work(&hw->usb_work); diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h index 2fecca2302f4..2e0bd24f997c 100644 --- a/drivers/staging/wlan-ng/p80211netdev.h +++ b/drivers/staging/wlan-ng/p80211netdev.h @@ -138,7 +138,7 @@ typedef struct p80211_frmrx_t { } p80211_frmrx_t; /* called by /proc/net/wireless */ -struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t * dev); +struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t *dev); /* wireless extensions' ioctls */ extern struct iw_handler_def p80211wext_handler_def; int p80211wext_event_associated(struct wlandevice *wlandev, int assoc); diff --git a/drivers/staging/wlan-ng/p80211wep.c b/drivers/staging/wlan-ng/p80211wep.c index 77e50a4aa7e9..c4fabadf5d74 100644 --- a/drivers/staging/wlan-ng/p80211wep.c +++ b/drivers/staging/wlan-ng/p80211wep.c @@ -134,7 +134,7 @@ int wep_change_key(wlandevice_t *wlandev, int keynum, u8 *key, int keylen) return -1; #ifdef WEP_DEBUG - printk(KERN_DEBUG "WEP key %d len %d = %*phC\n", keynum, keylen, + pr_debug("WEP key %d len %d = %*phC\n", keynum, keylen, 8, key); #endif @@ -182,7 +182,7 @@ int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, keylen += 3; /* add in IV bytes */ #ifdef WEP_DEBUG - printk(KERN_DEBUG "D %d: %*ph (%d %d) %*phC\n", len, 3, key, + pr_debug("D %d: %*ph (%d %d) %*phC\n", len, 3, key, keyidx, keylen, 5, key + 3); #endif @@ -259,7 +259,7 @@ int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, keylen += 3; /* add in IV bytes */ #ifdef WEP_DEBUG - printk(KERN_DEBUG "E %d (%d/%d %d) %*ph %*phC\n", len, + pr_debug("E %d (%d/%d %d) %*ph %*phC\n", len, iv[3], keynum, keylen, 3, key, 5, key + 3); #endif diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 3b3e17d3f6f5..b3ff603e6225 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -2070,7 +2070,6 @@ static void xgifb_remove(struct pci_dev *pdev) release_mem_region(xgifb_info->video_base, xgifb_info->video_size); pci_disable_device(pdev); framebuffer_release(fb_info); - pci_set_drvdata(pdev, NULL); } static struct pci_driver xgifb_driver = { diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c index 46dea3f10888..eed58f9a0ad5 100644 --- a/drivers/staging/xgifb/vb_setmode.c +++ b/drivers/staging/xgifb/vb_setmode.c @@ -5274,9 +5274,8 @@ void XGI_SenseCRT1(struct vb_device_info *pVBInfo) outb(0x00, pVBInfo->P3c8); - for (i = 0; i < 256 * 3; i++) { + for (i = 0; i < 256 * 3; i++) outb(0x0F, (pVBInfo->P3c8 + 1)); /* DAC_TEST_PARMS */ - } mdelay(1); @@ -5291,9 +5290,8 @@ void XGI_SenseCRT1(struct vb_device_info *pVBInfo) /* avoid display something, set BLACK DAC if not restore DAC */ outb(0x00, pVBInfo->P3c8); - for (i = 0; i < 256 * 3; i++) { + for (i = 0; i < 256 * 3; i++) outb(0, (pVBInfo->P3c8 + 1)); - } xgifb_reg_set(pVBInfo->P3c4, 0x01, SR01); xgifb_reg_set(pVBInfo->P3d4, 0x63, CR63); diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h index 7168eedbd96a..f17e5b9bd333 100644 --- a/drivers/staging/xgifb/vb_table.h +++ b/drivers/staging/xgifb/vb_table.h @@ -1284,7 +1284,7 @@ static const struct SiS_LVDSData XGI_LVDS1024x768Des_1[] = { {0, 1048, 0, 771}, /* 04 (640x480x60Hz) */ {0, 1048, 0, 771}, /* 05 (800x600x60Hz) */ {0, 1048, 805, 770} /* 06 (1024x768x60Hz) */ -} ; +}; static const struct SiS_LVDSData XGI_LVDS1024x768Des_2[] = { {1142, 856, 622, 587}, /* 00 (320x200,320x400,640x200,640x400) */ diff --git a/drivers/staging/xillybus/Kconfig b/drivers/staging/xillybus/Kconfig index 8a4181f846a1..b15f778b4c68 100644 --- a/drivers/staging/xillybus/Kconfig +++ b/drivers/staging/xillybus/Kconfig @@ -16,14 +16,14 @@ if XILLYBUS config XILLYBUS_PCIE tristate "Xillybus over PCIe" - depends on XILLYBUS && PCI + depends on PCI help Set to M if you want Xillybus to use PCI Express for communicating with the FPGA. config XILLYBUS_OF tristate "Xillybus over Device Tree" - depends on XILLYBUS && OF_ADDRESS && OF_IRQ + depends on OF_ADDRESS && OF_IRQ help Set to M if you want Xillybus to find its resources from the Open Firmware Flattened Device Tree. If the target is an embedded diff --git a/drivers/staging/xillybus/xillybus_core.c b/drivers/staging/xillybus/xillybus_core.c index 7db6f03a0054..e77fb28440f8 100644 --- a/drivers/staging/xillybus/xillybus_core.c +++ b/drivers/staging/xillybus/xillybus_core.c @@ -112,8 +112,7 @@ static void malformed_message(u32 *buf) msg_bufno = (buf[0] >> 12) & 0x3ff; msg_data = buf[1] & 0xfffffff; - pr_warn("xillybus: Malformed message (skipping): " - "opcode=%d, channel=%03x, dir=%d, bufno=%03x, data=%07x\n", + pr_warn("xillybus: Malformed message (skipping): opcode=%d, channel=%03x, dir=%d, bufno=%03x, data=%07x\n", opcode, msg_channel, msg_dir, msg_bufno, msg_data); } @@ -153,15 +152,13 @@ irqreturn_t xillybus_isr(int irq, void *data) for (i = 0; i < buf_size; i += 2) if (((buf[i+1] >> 28) & 0xf) != ep->msg_counter) { malformed_message(&buf[i]); - pr_warn("xillybus: Sending a NACK on " - "counter %x (instead of %x) on entry %d\n", + pr_warn("xillybus: Sending a NACK on counter %x (instead of %x) on entry %d\n", ((buf[i+1] >> 28) & 0xf), ep->msg_counter, i/2); if (++ep->failed_messages > 10) - pr_err("xillybus: Lost sync with " - "interrupt messages. Stopping.\n"); + pr_err("xillybus: Lost sync with interrupt messages. Stopping.\n"); else { ep->ephw->hw_sync_sgl_for_device( ep, @@ -283,13 +280,7 @@ irqreturn_t xillybus_isr(int irq, void *data) case XILLYMSG_OPCODE_FATAL_ERROR: ep->fatal_error = 1; wake_up_interruptible(&ep->ep_wait); /* For select() */ - pr_err("xillybus: FPGA reported a fatal " - "error. This means that the low-level " - "communication with the device has failed. " - "This hardware problem is most likely " - "unrelated to xillybus (neither kernel " - "module nor FPGA core), but reports are " - "still welcome. All I/O is aborted.\n"); + pr_err("xillybus: FPGA reported a fatal error. This means that the low-level communication with the device has failed. This hardware problem is most likely unrelated to xillybus (neither kernel module nor FPGA core), but reports are still welcome. All I/O is aborted.\n"); break; default: malformed_message(&buf[i]); @@ -486,8 +477,7 @@ static int xilly_setupchannels(struct xilly_endpoint *ep, if ((channelnum > ep->num_channels) || ((channelnum == 0) && !is_writebuf)) { - pr_err("xillybus: IDT requests channel out " - "of range. Aborting.\n"); + pr_err("xillybus: IDT requests channel out of range. Aborting.\n"); return -ENODEV; } @@ -565,9 +555,7 @@ static int xilly_setupchannels(struct xilly_endpoint *ep, */ if ((left_of_wr_salami < bytebufsize) && (left_of_wr_salami > 0)) { - pr_err("xillybus: " - "Corrupt buffer allocation " - "in IDT. Aborting.\n"); + pr_err("xillybus: Corrupt buffer allocation in IDT. Aborting.\n"); return -ENODEV; } @@ -644,9 +632,7 @@ static int xilly_setupchannels(struct xilly_endpoint *ep, */ if ((left_of_rd_salami < bytebufsize) && (left_of_rd_salami > 0)) { - pr_err("xillybus: " - "Corrupt buffer allocation " - "in IDT. Aborting.\n"); + pr_err("xillybus: Corrupt buffer allocation in IDT. Aborting.\n"); return -ENODEV; } @@ -706,16 +692,14 @@ static int xilly_setupchannels(struct xilly_endpoint *ep, } if (!msg_buf_done) { - pr_err("xillybus: Corrupt IDT: No message buffer. " - "Aborting.\n"); + pr_err("xillybus: Corrupt IDT: No message buffer. Aborting.\n"); return -ENODEV; } return 0; memfail: - pr_err("xillybus: Failed to allocate write buffer memory. " - "Aborting.\n"); + pr_err("xillybus: Failed to allocate write buffer memory. Aborting.\n"); return -ENOMEM; dmafail: pr_err("xillybus: Failed to map DMA memory!. Aborting.\n"); @@ -745,8 +729,7 @@ static void xilly_scan_idt(struct xilly_endpoint *endpoint, scan++; if (scan > end_of_idt) { - pr_err("xillybus: IDT device name list overflow. " - "Aborting.\n"); + pr_err("xillybus: IDT device name list overflow. Aborting.\n"); idt_handle->chandesc = NULL; return; } else @@ -757,8 +740,7 @@ static void xilly_scan_idt(struct xilly_endpoint *endpoint, if (len & 0x03) { idt_handle->chandesc = NULL; - pr_err("xillybus: Corrupt IDT device name list. " - "Aborting.\n"); + pr_err("xillybus: Corrupt IDT device name list. Aborting.\n"); } idt_handle->entries = len >> 2; @@ -803,8 +785,7 @@ static int xilly_obtain_idt(struct xilly_endpoint *endpoint) DMA_FROM_DEVICE); if (channel->wr_buffers[0]->end_offset != endpoint->idtlen) { - pr_err("xillybus: IDT length mismatch (%d != %d). " - "Aborting.\n", + pr_err("xillybus: IDT length mismatch (%d != %d). Aborting.\n", channel->wr_buffers[0]->end_offset, endpoint->idtlen); rc = -ENODEV; return rc; @@ -821,9 +802,7 @@ static int xilly_obtain_idt(struct xilly_endpoint *endpoint) /* Check version number. Accept anything below 0x82 for now. */ if (*version > 0x82) { - pr_err("xillybus: No support for IDT version 0x%02x. " - "Maybe the xillybus driver needs an upgarde. " - "Aborting.\n", + pr_err("xillybus: No support for IDT version 0x%02x. Maybe the xillybus driver needs an upgarde. Aborting.\n", (int) *version); rc = -ENODEV; return rc; @@ -1312,9 +1291,7 @@ static int xillybus_myflush(struct xilly_channel *channel, long timeout) channel->rd_wait, (!channel->rd_full), timeout) == 0) { - pr_warn("xillybus: " - "Timed out while flushing. " - "Output data may be lost.\n"); + pr_warn("xillybus: Timed out while flushing. Output data may be lost.\n"); rc = -ETIMEDOUT; break; @@ -1354,11 +1331,9 @@ static void xillybus_autoflush(struct work_struct *work) rc = xillybus_myflush(channel, -1); if (rc == -EINTR) - pr_warn("xillybus: Autoflush failed because " - "work queue thread got a signal.\n"); + pr_warn("xillybus: Autoflush failed because work queue thread got a signal.\n"); else if (rc) - pr_err("xillybus: Autoflush failed under " - "weird circumstances.\n"); + pr_err("xillybus: Autoflush failed under weird circumstances.\n"); } @@ -1615,8 +1590,8 @@ static int xillybus_open(struct inode *inode, struct file *filp) mutex_unlock(&ep_list_lock); if (!endpoint) { - pr_err("xillybus: open() failed to find a device " - "for major=%d and minor=%d\n", major, minor); + pr_err("xillybus: open() failed to find a device for major=%d and minor=%d\n", + major, minor); return -ENODEV; } @@ -1642,15 +1617,13 @@ static int xillybus_open(struct inode *inode, struct file *filp) if ((filp->f_mode & FMODE_READ) && (filp->f_flags & O_NONBLOCK) && (channel->wr_synchronous || !channel->wr_allow_partial || !channel->wr_supports_nonempty)) { - pr_err("xillybus: open() failed: " - "O_NONBLOCK not allowed for read on this device\n"); + pr_err("xillybus: open() failed: O_NONBLOCK not allowed for read on this device\n"); return -ENODEV; } if ((filp->f_mode & FMODE_WRITE) && (filp->f_flags & O_NONBLOCK) && (channel->rd_synchronous || !channel->rd_allow_partial)) { - pr_err("xillybus: open() failed: " - "O_NONBLOCK not allowed for write on this device\n"); + pr_err("xillybus: open() failed: O_NONBLOCK not allowed for write on this device\n"); return -ENODEV; } @@ -1765,8 +1738,7 @@ static int xillybus_release(struct inode *inode, struct file *filp) rc = mutex_lock_interruptible(&channel->rd_mutex); if (rc) { - pr_warn("xillybus: Failed to close file. " - "Hardware left in messy state.\n"); + pr_warn("xillybus: Failed to close file. Hardware left in messy state.\n"); return rc; } @@ -1791,8 +1763,7 @@ static int xillybus_release(struct inode *inode, struct file *filp) if (filp->f_mode & FMODE_READ) { rc = mutex_lock_interruptible(&channel->wr_mutex); if (rc) { - pr_warn("xillybus: Failed to close file. " - "Hardware left in messy state.\n"); + pr_warn("xillybus: Failed to close file. Hardware left in messy state.\n"); return rc; } @@ -1853,10 +1824,7 @@ static int xillybus_release(struct inode *inode, struct file *filp) if (channel->wr_sleepy) { mutex_unlock(&channel->wr_mutex); - pr_warn("xillybus: Hardware failed to " - "respond to close command, " - "therefore left in " - "messy state.\n"); + pr_warn("xillybus: Hardware failed to respond to close command, therefore left in messy state.\n"); return -EINTR; } } @@ -2057,8 +2025,7 @@ static int xillybus_init_chrdev(struct xilly_endpoint *endpoint, "%s", devname); if (IS_ERR(device)) { - pr_warn("xillybus: Failed to create %s " - "device. Aborting.\n", devname); + pr_warn("xillybus: Failed to create %s device. Aborting.\n", devname); goto error3; } } @@ -2141,8 +2108,7 @@ static int xilly_quiesce(struct xilly_endpoint *endpoint) XILLY_TIMEOUT); if (endpoint->idtlen < 0) { - pr_err("xillybus: Failed to quiesce the device on " - "exit. Quitting while leaving a mess.\n"); + pr_err("xillybus: Failed to quiesce the device on exit. Quitting while leaving a mess.\n"); return -ENODEV; } return 0; /* Success */ diff --git a/drivers/staging/xillybus/xillybus_of.c b/drivers/staging/xillybus/xillybus_of.c index 92c2931f4348..2ae045e332d4 100644 --- a/drivers/staging/xillybus/xillybus_of.c +++ b/drivers/staging/xillybus/xillybus_of.c @@ -198,15 +198,4 @@ static struct platform_driver xillybus_platform_driver = { }, }; -static int __init xillybus_of_init(void) -{ - return platform_driver_register(&xillybus_platform_driver); -} - -static void __exit xillybus_of_exit(void) -{ - platform_driver_unregister(&xillybus_platform_driver); -} - -module_init(xillybus_of_init); -module_exit(xillybus_of_exit); +module_platform_driver(xillybus_platform_driver); diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig index 7fab032298f3..0ae13cd0908e 100644 --- a/drivers/staging/zsmalloc/Kconfig +++ b/drivers/staging/zsmalloc/Kconfig @@ -1,5 +1,6 @@ config ZSMALLOC bool "Memory allocator for compressed pages" + depends on MMU default n help zsmalloc is a slab-based memory allocator designed to store diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 32ba45158d39..a265af294ea4 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -47,11 +47,13 @@ struct hid_sensor_hub_attribute_info { * @hdev: Stores the hid instance. * @vendor_id: Vendor id of hub device. * @product_id: Product id of hub device. + * @ref_cnt: Number of MFD clients have opened this device */ struct hid_sensor_hub_device { struct hid_device *hdev; u32 vendor_id; u32 product_id; + int ref_cnt; }; /** @@ -74,6 +76,22 @@ struct hid_sensor_hub_callbacks { void *priv); }; +/** +* sensor_hub_device_open() - Open hub device +* @hsdev: Hub device instance. +* +* Used to open hid device for sensor hub. +*/ +int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev); + +/** +* sensor_hub_device_clode() - Close hub device +* @hsdev: Hub device instance. +* +* Used to clode hid device for sensor hub. +*/ +void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev); + /* Registration functions */ /** diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 2bac0eb8948d..15607b45221a 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -11,6 +11,7 @@ #define _IIO_BUFFER_GENERIC_H_ #include <linux/sysfs.h> #include <linux/iio/iio.h> +#include <linux/kref.h> #ifdef CONFIG_IIO_BUFFER @@ -26,6 +27,8 @@ struct iio_buffer; * @set_bytes_per_datum:set number of bytes per datum * @get_length: get number of datums in buffer * @set_length: set number of datums in buffer + * @release: called when the last reference to the buffer is dropped, + * should free all resources allocated by the buffer. * * The purpose of this structure is to make the buffer element * modular as event for a given driver, different usecases may require @@ -36,7 +39,7 @@ struct iio_buffer; * any of them not existing. **/ struct iio_buffer_access_funcs { - int (*store_to)(struct iio_buffer *buffer, u8 *data); + int (*store_to)(struct iio_buffer *buffer, const void *data); int (*read_first_n)(struct iio_buffer *buffer, size_t n, char __user *buf); @@ -47,6 +50,8 @@ struct iio_buffer_access_funcs { int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd); int (*get_length)(struct iio_buffer *buffer); int (*set_length)(struct iio_buffer *buffer, int length); + + void (*release)(struct iio_buffer *buffer); }; /** @@ -67,6 +72,7 @@ struct iio_buffer_access_funcs { * @demux_list: [INTERN] list of operations required to demux the scan. * @demux_bounce: [INTERN] buffer for doing gather from incoming scan. * @buffer_list: [INTERN] entry in the devices list of current buffers. + * @ref: [INTERN] reference count of the buffer. */ struct iio_buffer { int length; @@ -81,8 +87,9 @@ struct iio_buffer { bool stufftoread; const struct attribute_group *attrs; struct list_head demux_list; - unsigned char *demux_bounce; + void *demux_bounce; struct list_head buffer_list; + struct kref ref; }; /** @@ -120,7 +127,32 @@ int iio_scan_mask_set(struct iio_dev *indio_dev, * @indio_dev: iio_dev structure for device. * @data: Full scan. */ -int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data); +int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data); + +/* + * iio_push_to_buffers_with_timestamp() - push data and timestamp to buffers + * @indio_dev: iio_dev structure for device. + * @data: sample data + * @timestamp: timestamp for the sample data + * + * Pushes data to the IIO device's buffers. If timestamps are enabled for the + * device the function will store the supplied timestamp as the last element in + * the sample data buffer before pushing it to the device buffers. The sample + * data buffer needs to be large enough to hold the additional timestamp + * (usually the buffer should be indio->scan_bytes bytes large). + * + * Returns 0 on success, a negative error code otherwise. + */ +static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev, + void *data, int64_t timestamp) +{ + if (indio_dev->scan_timestamp) { + size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1; + ((int64_t *)data)[ts_offset] = timestamp; + } + + return iio_push_to_buffers(indio_dev, data); +} int iio_update_demux(struct iio_dev *indio_dev); @@ -174,11 +206,27 @@ ssize_t iio_buffer_show_enable(struct device *dev, iio_buffer_show_enable, \ iio_buffer_store_enable) -int iio_sw_buffer_preenable(struct iio_dev *indio_dev); - bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, const unsigned long *mask); +struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer); +void iio_buffer_put(struct iio_buffer *buffer); + +/** + * iio_device_attach_buffer - Attach a buffer to a IIO device + * @indio_dev: The device the buffer should be attached to + * @buffer: The buffer to attach to the device + * + * This function attaches a buffer to a IIO device. The buffer stays attached to + * the device until the device is freed. The function should only be called at + * most once per device. + */ +static inline void iio_device_attach_buffer(struct iio_dev *indio_dev, + struct iio_buffer *buffer) +{ + indio_dev->buffer = iio_buffer_get(buffer); +} + #else /* CONFIG_IIO_BUFFER */ static inline int iio_buffer_register(struct iio_dev *indio_dev, @@ -191,6 +239,9 @@ static inline int iio_buffer_register(struct iio_dev *indio_dev, static inline void iio_buffer_unregister(struct iio_dev *indio_dev) {} +static inline void iio_buffer_get(struct iio_buffer *buffer) {} +static inline void iio_buffer_put(struct iio_buffer *buffer) {} + #endif /* CONFIG_IIO_BUFFER */ #endif /* _IIO_BUFFER_GENERIC_H_ */ diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index e51f65480ea5..3c005eb3a0a4 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -16,6 +16,7 @@ #include <linux/irqreturn.h> #include <linux/iio/trigger.h> #include <linux/bitops.h> +#include <linux/regulator/consumer.h> #include <linux/platform_data/st_sensors_pdata.h> @@ -184,6 +185,7 @@ struct st_sensors { u8 wai; char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME]; struct iio_chan_spec *ch; + int num_ch; struct st_sensor_odr odr; struct st_sensor_power pw; struct st_sensor_axis enable_axis; @@ -200,6 +202,8 @@ struct st_sensors { * @trig: The trigger in use by the core driver. * @sensor: Pointer to the current sensor struct in use. * @current_fullscale: Maximum range of measure by the sensor. + * @vdd: Pointer to sensor's Vdd power supply + * @vdd_io: Pointer to sensor's Vdd-IO power supply * @enabled: Status of the sensor (false->off, true->on). * @multiread_bit: Use or not particular bit for [I2C/SPI] multiread. * @buffer_data: Data used by buffer part. @@ -215,6 +219,8 @@ struct st_sensor_data { struct iio_trigger *trig; struct st_sensors *sensor; struct st_sensor_fullscale_avl *current_fullscale; + struct regulator *vdd; + struct regulator *vdd_io; bool enabled; bool multiread_bit; diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 833926c91aa8..2752b1fd12be 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -77,7 +77,7 @@ struct iio_cb_buffer; * fail. */ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, - int (*cb)(u8 *data, + int (*cb)(const void *data, void *private), void *private); /** diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h index 13ce220c7003..5dab2c41031f 100644 --- a/include/linux/iio/events.h +++ b/include/linux/iio/events.h @@ -26,20 +26,6 @@ struct iio_event_data { #define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int) -enum iio_event_type { - IIO_EV_TYPE_THRESH, - IIO_EV_TYPE_MAG, - IIO_EV_TYPE_ROC, - IIO_EV_TYPE_THRESH_ADAPTIVE, - IIO_EV_TYPE_MAG_ADAPTIVE, -}; - -enum iio_event_direction { - IIO_EV_DIR_EITHER, - IIO_EV_DIR_RISING, - IIO_EV_DIR_FALLING, -}; - /** * IIO_EVENT_CODE() - create event identifier * @chan_type: Type of the channel. Should be one of enum iio_chan_type. diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 2103cc32a5fb..256a90a1bea6 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -36,6 +36,14 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_PHASE, IIO_CHAN_INFO_HARDWAREGAIN, IIO_CHAN_INFO_HYSTERESIS, + IIO_CHAN_INFO_INT_TIME, +}; + +enum iio_shared_by { + IIO_SEPARATE, + IIO_SHARED_BY_TYPE, + IIO_SHARED_BY_DIR, + IIO_SHARED_BY_ALL }; enum iio_endian { @@ -57,7 +65,7 @@ struct iio_dev; */ struct iio_chan_spec_ext_info { const char *name; - bool shared; + enum iio_shared_by shared; ssize_t (*read)(struct iio_dev *, uintptr_t private, struct iio_chan_spec const *, char *buf); ssize_t (*write)(struct iio_dev *, uintptr_t private, @@ -125,12 +133,35 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, #define IIO_ENUM_AVAILABLE(_name, _e) \ { \ .name = (_name "_available"), \ - .shared = true, \ + .shared = IIO_SHARED_BY_TYPE, \ .read = iio_enum_available_read, \ .private = (uintptr_t)(_e), \ } /** + * struct iio_event_spec - specification for a channel event + * @type: Type of the event + * @dir: Direction of the event + * @mask_separate: Bit mask of enum iio_event_info values. Attributes + * set in this mask will be registered per channel. + * @mask_shared_by_type: Bit mask of enum iio_event_info values. Attributes + * set in this mask will be shared by channel type. + * @mask_shared_by_dir: Bit mask of enum iio_event_info values. Attributes + * set in this mask will be shared by channel type and + * direction. + * @mask_shared_by_all: Bit mask of enum iio_event_info values. Attributes + * set in this mask will be shared by all channels. + */ +struct iio_event_spec { + enum iio_event_type type; + enum iio_event_direction dir; + unsigned long mask_separate; + unsigned long mask_shared_by_type; + unsigned long mask_shared_by_dir; + unsigned long mask_shared_by_all; +}; + +/** * struct iio_chan_spec - specification of a single channel * @type: What type of measurement is the channel making. * @channel: What number do we wish to assign the channel. @@ -146,13 +177,18 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, * shift: Shift right by this before masking out * realbits. * endianness: little or big endian - * @info_mask: What information is to be exported about this channel. - * This includes calibbias, scale etc. * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_shared_by_type: What information is to be exported that is shared -* by all channels of the same type. + * by all channels of the same type. + * @info_mask_shared_by_dir: What information is to be exported that is shared + * by all channels of the same direction. + * @info_mask_shared_by_all: What information is to be exported that is shared + * by all channels. * @event_mask: What events can this channel produce. + * @event_spec: Array of events which should be registered for this + * channel. + * @num_event_specs: Size of the event_spec array. * @ext_info: Array of extended info attributes for this channel. * The array is NULL terminated, the last element should * have its name field set to NULL. @@ -186,10 +222,13 @@ struct iio_chan_spec { u8 shift; enum iio_endian endianness; } scan_type; - long info_mask; long info_mask_separate; long info_mask_shared_by_type; + long info_mask_shared_by_dir; + long info_mask_shared_by_all; long event_mask; + const struct iio_event_spec *event_spec; + unsigned int num_event_specs; const struct iio_chan_spec_ext_info *ext_info; const char *extend_name; const char *datasheet_name; @@ -212,7 +251,9 @@ static inline bool iio_channel_has_info(const struct iio_chan_spec *chan, enum iio_chan_info_enum type) { return (chan->info_mask_separate & BIT(type)) | - (chan->info_mask_shared_by_type & BIT(type)); + (chan->info_mask_shared_by_type & BIT(type)) | + (chan->info_mask_shared_by_dir & BIT(type)) | + (chan->info_mask_shared_by_all & BIT(type)); } #define IIO_ST(si, rb, sb, sh) \ @@ -270,6 +311,12 @@ struct iio_dev; * is event dependant. event_code specifies which event. * @write_event_value: write the value associated with the event. * Meaning is event dependent. + * @read_event_config_new: find out if the event is enabled. New style interface. + * @write_event_config_new: set if the event is enabled. New style interface. + * @read_event_value_new: read a configuration value associated with the event. + * New style interface. + * @write_event_value_new: write a configuration value for the event. New style + * interface. * @validate_trigger: function to validate the trigger when the * current trigger gets changed. * @update_scan_mode: function to configure device and scan buffer when @@ -310,6 +357,30 @@ struct iio_info { int (*write_event_value)(struct iio_dev *indio_dev, u64 event_code, int val); + + int (*read_event_config_new)(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir); + + int (*write_event_config_new)(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state); + + int (*read_event_value_new)(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, int *val2); + + int (*write_event_value_new)(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int val, int val2); + int (*validate_trigger)(struct iio_dev *indio_dev, struct iio_trigger *trig); int (*update_scan_mode)(struct iio_dev *indio_dev, @@ -457,7 +528,7 @@ static inline void iio_device_put(struct iio_dev *indio_dev) { if (indio_dev) put_device(&indio_dev->dev); -}; +} /** * dev_to_iio_dev() - Get IIO device struct from a device struct @@ -593,7 +664,7 @@ static inline bool iio_buffer_enabled(struct iio_dev *indio_dev) { return indio_dev->currentmode & (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE); -}; +} /** * iio_get_debugfs_dentry() - helper function to get the debugfs_dentry @@ -603,12 +674,12 @@ static inline bool iio_buffer_enabled(struct iio_dev *indio_dev) static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) { return indio_dev->debugfs_dentry; -}; +} #else static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) { return NULL; -}; +} #endif int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h index 2958c960003a..8a1d18640ab9 100644 --- a/include/linux/iio/sysfs.h +++ b/include/linux/iio/sysfs.h @@ -100,6 +100,21 @@ struct iio_const_attr { #define IIO_CONST_ATTR_SAMP_FREQ_AVAIL(_string) \ IIO_CONST_ATTR(sampling_frequency_available, _string) +/** + * IIO_DEV_ATTR_INT_TIME_AVAIL - list available integration times + * @_show: output method for the attribute + **/ +#define IIO_DEV_ATTR_INT_TIME_AVAIL(_show) \ + IIO_DEVICE_ATTR(integration_time_available, S_IRUGO, _show, NULL, 0) +/** + * IIO_CONST_ATTR_INT_TIME_AVAIL - list available integration times + * @_string: frequency string for the attribute + * + * Constant version + **/ +#define IIO_CONST_ATTR_INT_TIME_AVAIL(_string) \ + IIO_CONST_ATTR(integration_time_available, _string) + #define IIO_DEV_ATTR_TEMP_RAW(_show) \ IIO_DEVICE_ATTR(in_temp_raw, S_IRUGO, _show, NULL, 0) diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 88bf0f0d27b4..4ac928ee31c5 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -54,6 +54,26 @@ enum iio_modifier { IIO_MOD_LIGHT_BLUE, }; +enum iio_event_type { + IIO_EV_TYPE_THRESH, + IIO_EV_TYPE_MAG, + IIO_EV_TYPE_ROC, + IIO_EV_TYPE_THRESH_ADAPTIVE, + IIO_EV_TYPE_MAG_ADAPTIVE, +}; + +enum iio_event_info { + IIO_EV_INFO_ENABLE, + IIO_EV_INFO_VALUE, + IIO_EV_INFO_HYSTERESIS, +}; + +enum iio_event_direction { + IIO_EV_DIR_EITHER, + IIO_EV_DIR_RISING, + IIO_EV_DIR_FALLING, +}; + #define IIO_VAL_INT 1 #define IIO_VAL_INT_PLUS_MICRO 2 #define IIO_VAL_INT_PLUS_NANO 3 diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index 25f2c611ab01..08cce7f96ab9 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -46,16 +46,24 @@ /* Step Enable */ #define STEPENB_MASK (0x1FFFF << 0) #define STEPENB(val) ((val) << 0) +#define ENB(val) (1 << (val)) +#define STPENB_STEPENB STEPENB(0x1FFFF) +#define STPENB_STEPENB_TC STEPENB(0x1FFF) /* IRQ enable */ #define IRQENB_HW_PEN BIT(0) #define IRQENB_FIFO0THRES BIT(2) +#define IRQENB_FIFO0OVRRUN BIT(3) +#define IRQENB_FIFO0UNDRFLW BIT(4) #define IRQENB_FIFO1THRES BIT(5) +#define IRQENB_FIFO1OVRRUN BIT(6) +#define IRQENB_FIFO1UNDRFLW BIT(7) #define IRQENB_PENUP BIT(9) /* Step Configuration */ #define STEPCONFIG_MODE_MASK (3 << 0) #define STEPCONFIG_MODE(val) ((val) << 0) +#define STEPCONFIG_MODE_SWCNT STEPCONFIG_MODE(1) #define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) #define STEPCONFIG_AVG_MASK (7 << 2) #define STEPCONFIG_AVG(val) ((val) << 2) @@ -123,6 +131,7 @@ #define ADC_CLK 3000000 #define TOTAL_STEPS 16 #define TOTAL_CHANNELS 8 +#define FIFO1_THRESHOLD 19 /* * ADC runs at 3MHz, and it takes |