mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
Staging driver patches for 3.16-rc1
Here is the big staging driver pull request for 3.16-rc1. Lots of stuff here, tons of cleanup patches, a few new drivers, and some removed as well, but I think we are still adding a few thousand more lines than we remove, due to the new drivers being bigger than the ones deleted. One notible bit of work did stand out, Jes Sorensen has gone on a tear, fixing up a wireless driver to be "more sane" than it originally was from the vendor, with over 500 patches merged here. Good stuff, and a number of users laptops are better off for it. All of this has been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEABECAAYFAlONXKQACgkQMUfUDdst+ynIwgCgq5pPIn+2aewaFK8rrN18xqls F3YAoNDYeqMpQepvRe50HcjRrgDvsV2n =VenO -----END PGP SIGNATURE----- Merge tag 'staging-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging into next Pull staging driver updates from Greg KH: "Here is the big staging driver pull request for 3.16-rc1. Lots of stuff here, tons of cleanup patches, a few new drivers, and some removed as well, but I think we are still adding a few thousand more lines than we remove, due to the new drivers being bigger than the ones deleted. One notible bit of work did stand out, Jes Sorensen has gone on a tear, fixing up a wireless driver to be "more sane" than it originally was from the vendor, with over 500 patches merged here. Good stuff, and a number of users laptops are better off for it. All of this has been in linux-next for a while" * tag 'staging-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1703 commits) staging: skein: fix sparse warning for static declarations staging/mt29f_spinand: coding style fixes staging: silicom: fix sparse warning for static variable staging: lustre: Fix coding style staging: android: binder.c: Use more appropriate functions for euid retrieval staging: lustre: fix integer as NULL pointer warnings Revert "staging: dgap: remove unneeded kfree() in dgap_tty_register_ports()" Staging: rtl8192u: r8192U_wx.c Fixed a misplaced brace staging: ion: shrink highmem pages on kswapd staging: ion: use compound pages on high order pages for system heap staging: ion: remove struct ion_page_pool_item staging: ion: simplify ion_page_pool_total() staging: ion: tidy up a bit staging: rtl8723au: Remove redundant casting in usb_ops_linux.c staging: rtl8723au: Remove redundant casting in rtl8723a_hal_init.c staging: rtl8723au: Remove redundant casting in rtw_xmit.c staging: rtl8723au: Remove redundant casting in rtw_wlan_util.c staging: rtl8723au: Remove redundant casting in rtw_sta_mgt.c staging: rtl8723au: Remove redundant casting in rtw_recv.c staging: rtl8723au: Remove redundant casting in rtw_mlme.c ...
This commit is contained in:
commit
5142c33ed8
@ -114,14 +114,17 @@ What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempX_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_x_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_y_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_z_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_ambient_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_raw
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Raw (unscaled no bias removal etc.) temperature measurement.
|
||||
If an axis is specified it generally means that the temperature
|
||||
sensor is associated with one part of a compound device (e.g.
|
||||
a gyroscope axis). Units after application of scale and offset
|
||||
a gyroscope axis). The ambient and object modifiers distinguish
|
||||
between ambient (reference) and distant temperature for contact-
|
||||
less measurements. Units after application of scale and offset
|
||||
are milli degrees Celsius.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempX_input
|
||||
@ -210,6 +213,14 @@ Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Scaled humidity measurement in milli percent.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_X_mean_raw
|
||||
KernelVersion: 3.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Averaged raw measurement from channel X. The number of values
|
||||
used for averaging is device specific. The converting rules for
|
||||
normal raw values also applies to the averaged raw values.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
|
||||
@ -784,6 +795,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressure_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_en
|
||||
KernelVersion: 2.6.37
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
@ -799,6 +811,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressure_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_type
|
||||
KernelVersion: 2.6.37
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
@ -845,6 +858,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressure_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_index
|
||||
KernelVersion: 2.6.37
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
@ -881,6 +895,25 @@ Description:
|
||||
on-chip EEPROM. After power-up or chip reset the device will
|
||||
automatically load the saved configuration.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_input
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_raw
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_mean_raw
|
||||
KernelVersion: 3.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Illuminance measurement, units after application of scale
|
||||
and offset are lux.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_intensityY_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_ir_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_both_raw
|
||||
KernelVersion: 3.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Unit-less light intensity. Modifiers both and ir indicate
|
||||
that measurements contains visible and infrared light
|
||||
components or just infrared light, respectively.
|
||||
|
||||
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
|
||||
@ -891,3 +924,12 @@ Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute is used to get/set the integration time in
|
||||
seconds.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_quaternion_raw
|
||||
KernelVersion: 3.15
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Raw value of quaternion components using a format
|
||||
x y z w. Here x, y, and z component represents the axis about
|
||||
which a rotation will occur and w component represents the
|
||||
amount of rotation.
|
||||
|
16
Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
Normal file
16
Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
Normal file
@ -0,0 +1,16 @@
|
||||
What /sys/bus/iio/devices/iio:deviceX/in_proximity_raw
|
||||
Date: March 2014
|
||||
KernelVersion: 3.15
|
||||
Contact: Matt Ranostay <mranostay@gmail.com>
|
||||
Description:
|
||||
Get the current distance in meters of storm (1km steps)
|
||||
1000-40000 = distance in meters
|
||||
|
||||
What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
|
||||
Date: March 2014
|
||||
KernelVersion: 3.15
|
||||
Contact: Matt Ranostay <mranostay@gmail.com>
|
||||
Description:
|
||||
Show or set the gain boost of the amp, from 0-31 range.
|
||||
18 = indoors (default)
|
||||
14 = outdoors
|
28
Documentation/devicetree/bindings/iio/proximity/as3935.txt
Normal file
28
Documentation/devicetree/bindings/iio/proximity/as3935.txt
Normal file
@ -0,0 +1,28 @@
|
||||
Austrian Microsystems AS3935 Franklin lightning sensor device driver
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "ams,as3935"
|
||||
- reg: SPI chip select number for the device
|
||||
- spi-cpha: SPI Mode 1. Refer to spi/spi-bus.txt for generic SPI
|
||||
slave node bindings.
|
||||
- interrupt-parent : should be the phandle for the interrupt controller
|
||||
- interrupts : the sole interrupt generated by the device
|
||||
|
||||
Refer to interrupt-controller/interrupts.txt for generic
|
||||
interrupt client node bindings.
|
||||
|
||||
Optional properties:
|
||||
- ams,tuning-capacitor-pf: Calibration tuning capacitor stepping
|
||||
value 0 - 120pF. This will require using the calibration data from
|
||||
the manufacturer.
|
||||
|
||||
Example:
|
||||
|
||||
as3935@0 {
|
||||
compatible = "ams,as3935";
|
||||
reg = <0>;
|
||||
spi-cpha;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <16 1>;
|
||||
ams,tuning-capacitor-pf = <80>;
|
||||
};
|
@ -61,6 +61,7 @@ Required properties:
|
||||
Optional properties:
|
||||
- interface_pix_fmt: How this display is connected to the
|
||||
display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
|
||||
and "lvds666".
|
||||
- edid: verbatim EDID data block describing attached display.
|
||||
- ddc: phandle describing the i2c bus handling the display data
|
||||
channel
|
||||
|
@ -13,6 +13,7 @@ allwinner Allwinner Technology Co., Ltd.
|
||||
altr Altera Corp.
|
||||
amcc Applied Micro Circuits Corporation (APM, formally AMCC)
|
||||
amd Advanced Micro Devices (AMD), Inc.
|
||||
ams AMS AG
|
||||
amstaos AMS-Taos Inc.
|
||||
apm Applied Micro Circuits Corporation (APM)
|
||||
arm ARM Ltd.
|
||||
|
@ -236,6 +236,9 @@ certainly invest a bit more effort into libata core layer).
|
||||
MEM
|
||||
devm_kzalloc()
|
||||
devm_kfree()
|
||||
devm_kmemdup()
|
||||
devm_get_free_pages()
|
||||
devm_free_pages()
|
||||
|
||||
IIO
|
||||
devm_iio_device_alloc()
|
||||
|
11
MAINTAINERS
11
MAINTAINERS
@ -2779,12 +2779,14 @@ F: sound/soc/codecs/da[79]*.[ch]
|
||||
|
||||
DIGI NEO AND CLASSIC PCI PRODUCTS
|
||||
M: Lidza Louina <lidza.louina@gmail.com>
|
||||
M: Mark Hounschell <markh@compro.net>
|
||||
L: driverdev-devel@linuxdriverproject.org
|
||||
S: Maintained
|
||||
F: drivers/staging/dgnc/
|
||||
|
||||
DIGI EPCA PCI PRODUCTS
|
||||
M: Lidza Louina <lidza.louina@gmail.com>
|
||||
M: Mark Hounschell <markh@compro.net>
|
||||
L: driverdev-devel@linuxdriverproject.org
|
||||
S: Maintained
|
||||
F: drivers/staging/dgap/
|
||||
@ -8491,7 +8493,7 @@ S: Maintained
|
||||
F: drivers/staging/olpc_dcon/
|
||||
|
||||
STAGING - OZMO DEVICES USB OVER WIFI DRIVER
|
||||
M: Rupesh Gujare <rupesh.gujare@atmel.com>
|
||||
M: Shigekatsu Tateno <shigekatsu.tateno@atmel.com>
|
||||
S: Maintained
|
||||
F: drivers/staging/ozwpan/
|
||||
|
||||
@ -8506,6 +8508,13 @@ M: Florian Schilhabel <florian.c.schilhabel@googlemail.com>.
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/rtl8712/
|
||||
|
||||
STAGING - REALTEK RTL8723U WIRELESS DRIVER
|
||||
M: Larry Finger <Larry.Finger@lwfinger.net>
|
||||
M: Jes Sorensen <Jes.Sorensen@redhat.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/staging/rtl8723au/
|
||||
|
||||
STAGING - SILICON MOTION SM7XX FRAME BUFFER DRIVER
|
||||
M: Teddy Wang <teddy.wang@siliconmotion.com.cn>
|
||||
S: Odd Fixes
|
||||
|
@ -415,7 +415,6 @@ config X86_UV
|
||||
|
||||
config X86_GOLDFISH
|
||||
bool "Goldfish (Virtual Platform)"
|
||||
depends on X86_32
|
||||
depends on X86_EXTENDED_PLATFORM
|
||||
---help---
|
||||
Enable support for the Goldfish virtual platform used primarily
|
||||
|
@ -831,3 +831,100 @@ void devm_kfree(struct device *dev, void *p)
|
||||
WARN_ON(rc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_kfree);
|
||||
|
||||
/**
|
||||
* devm_kmemdup - Resource-managed kmemdup
|
||||
* @dev: Device this memory belongs to
|
||||
* @src: Memory region to duplicate
|
||||
* @len: Memory region length
|
||||
* @gfp: GFP mask to use
|
||||
*
|
||||
* Duplicate region of a memory using resource managed kmalloc
|
||||
*/
|
||||
void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = devm_kmalloc(dev, len, gfp);
|
||||
if (p)
|
||||
memcpy(p, src, len);
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_kmemdup);
|
||||
|
||||
struct pages_devres {
|
||||
unsigned long addr;
|
||||
unsigned int order;
|
||||
};
|
||||
|
||||
static int devm_pages_match(struct device *dev, void *res, void *p)
|
||||
{
|
||||
struct pages_devres *devres = res;
|
||||
struct pages_devres *target = p;
|
||||
|
||||
return devres->addr == target->addr;
|
||||
}
|
||||
|
||||
static void devm_pages_release(struct device *dev, void *res)
|
||||
{
|
||||
struct pages_devres *devres = res;
|
||||
|
||||
free_pages(devres->addr, devres->order);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_get_free_pages - Resource-managed __get_free_pages
|
||||
* @dev: Device to allocate memory for
|
||||
* @gfp_mask: Allocation gfp flags
|
||||
* @order: Allocation size is (1 << order) pages
|
||||
*
|
||||
* Managed get_free_pages. Memory allocated with this function is
|
||||
* automatically freed on driver detach.
|
||||
*
|
||||
* RETURNS:
|
||||
* Address of allocated memory on success, 0 on failure.
|
||||
*/
|
||||
|
||||
unsigned long devm_get_free_pages(struct device *dev,
|
||||
gfp_t gfp_mask, unsigned int order)
|
||||
{
|
||||
struct pages_devres *devres;
|
||||
unsigned long addr;
|
||||
|
||||
addr = __get_free_pages(gfp_mask, order);
|
||||
|
||||
if (unlikely(!addr))
|
||||
return 0;
|
||||
|
||||
devres = devres_alloc(devm_pages_release,
|
||||
sizeof(struct pages_devres), GFP_KERNEL);
|
||||
if (unlikely(!devres)) {
|
||||
free_pages(addr, order);
|
||||
return 0;
|
||||
}
|
||||
|
||||
devres->addr = addr;
|
||||
devres->order = order;
|
||||
|
||||
devres_add(dev, devres);
|
||||
return addr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_get_free_pages);
|
||||
|
||||
/**
|
||||
* devm_free_pages - Resource-managed free_pages
|
||||
* @dev: Device this memory belongs to
|
||||
* @addr: Memory to free
|
||||
*
|
||||
* Free memory allocated with devm_get_free_pages(). Unlike free_pages,
|
||||
* there is no need to supply the @order.
|
||||
*/
|
||||
void devm_free_pages(struct device *dev, unsigned long addr)
|
||||
{
|
||||
struct pages_devres devres = { .addr = addr };
|
||||
|
||||
WARN_ON(devres_release(dev, devm_pages_release, devm_pages_match,
|
||||
&devres));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_free_pages);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
menuconfig IIO
|
||||
tristate "Industrial I/O support"
|
||||
select ANON_INODES
|
||||
help
|
||||
The industrial I/O subsystem provides a unified framework for
|
||||
drivers for many different types of embedded sensors using a
|
||||
@ -74,6 +75,7 @@ if IIO_TRIGGER
|
||||
source "drivers/iio/trigger/Kconfig"
|
||||
endif #IIO_TRIGGER
|
||||
source "drivers/iio/pressure/Kconfig"
|
||||
source "drivers/iio/proximity/Kconfig"
|
||||
source "drivers/iio/temperature/Kconfig"
|
||||
|
||||
endif # IIO
|
||||
|
@ -24,5 +24,6 @@ obj-y += light/
|
||||
obj-y += magnetometer/
|
||||
obj-y += orientation/
|
||||
obj-y += pressure/
|
||||
obj-y += proximity/
|
||||
obj-y += temperature/
|
||||
obj-y += trigger/
|
||||
|
@ -65,4 +65,16 @@ config KXSD9
|
||||
Say yes here to build support for the Kionix KXSD9 accelerometer.
|
||||
Currently this only supports the device via an SPI interface.
|
||||
|
||||
config MMA8452
|
||||
tristate "Freescale MMA8452Q Accelerometer Driver"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for the Freescale MMA8452Q 3-axis
|
||||
accelerometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mma8452.
|
||||
|
||||
endmenu
|
||||
|
@ -6,6 +6,7 @@
|
||||
obj-$(CONFIG_BMA180) += bma180.o
|
||||
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
|
||||
obj-$(CONFIG_KXSD9) += kxsd9.o
|
||||
obj-$(CONFIG_MMA8452) += mma8452.o
|
||||
|
||||
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
|
||||
st_accel-y := st_accel_core.o
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -42,6 +43,10 @@ struct accel_3d_state {
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
|
||||
u32 accel_val[ACCEL_3D_CHANNEL_MAX];
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
int value_offset;
|
||||
};
|
||||
|
||||
static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = {
|
||||
@ -56,6 +61,7 @@ static const struct iio_chan_spec accel_3d_channels[] = {
|
||||
.type = IIO_ACCEL,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_X,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -65,6 +71,7 @@ static const struct iio_chan_spec accel_3d_channels[] = {
|
||||
.type = IIO_ACCEL,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_Y,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -74,6 +81,7 @@ static const struct iio_chan_spec accel_3d_channels[] = {
|
||||
.type = IIO_ACCEL,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_Z,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -104,31 +112,42 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
|
||||
u32 address;
|
||||
int ret;
|
||||
int ret_type;
|
||||
s32 poll_value;
|
||||
|
||||
*val = 0;
|
||||
*val2 = 0;
|
||||
switch (mask) {
|
||||
case 0:
|
||||
poll_value = hid_sensor_read_poll_value(
|
||||
&accel_state->common_attributes);
|
||||
if (poll_value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
hid_sensor_power_state(&accel_state->common_attributes, true);
|
||||
msleep_interruptible(poll_value * 2);
|
||||
report_id = accel_state->accel[chan->scan_index].report_id;
|
||||
address = accel_3d_addresses[chan->scan_index];
|
||||
if (report_id >= 0)
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
accel_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_ACCEL_3D, address,
|
||||
report_id);
|
||||
accel_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_ACCEL_3D, address,
|
||||
report_id);
|
||||
else {
|
||||
*val = 0;
|
||||
hid_sensor_power_state(&accel_state->common_attributes,
|
||||
false);
|
||||
return -EINVAL;
|
||||
}
|
||||
hid_sensor_power_state(&accel_state->common_attributes, false);
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = accel_state->accel[CHANNEL_SCAN_INDEX_X].units;
|
||||
ret_type = IIO_VAL_INT;
|
||||
*val = accel_state->scale_pre_decml;
|
||||
*val2 = accel_state->scale_post_decml;
|
||||
ret_type = accel_state->scale_precision;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = hid_sensor_convert_exponent(
|
||||
accel_state->accel[CHANNEL_SCAN_INDEX_X].unit_expo);
|
||||
*val = accel_state->value_offset;
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
@ -197,9 +216,8 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct accel_3d_state *accel_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "accel_3d_proc_event [%d]\n",
|
||||
accel_state->common_attributes.data_ready);
|
||||
if (accel_state->common_attributes.data_ready)
|
||||
dev_dbg(&indio_dev->dev, "accel_3d_proc_event\n");
|
||||
if (atomic_read(&accel_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
accel_state->accel_val,
|
||||
sizeof(accel_state->accel_val));
|
||||
@ -262,6 +280,11 @@ static int accel_3d_parse_report(struct platform_device *pdev,
|
||||
st->accel[1].index, st->accel[1].report_id,
|
||||
st->accel[2].index, st->accel[2].report_id);
|
||||
|
||||
st->scale_precision = hid_sensor_format_scale(
|
||||
HID_USAGE_SENSOR_ACCEL_3D,
|
||||
&st->accel[CHANNEL_SCAN_INDEX_X],
|
||||
&st->scale_pre_decml, &st->scale_post_decml);
|
||||
|
||||
/* Set Sensitivity field ids, when there is no individual modifier */
|
||||
if (st->common_attributes.sensitivity.index < 0) {
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
@ -333,7 +356,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
goto error_free_dev_mem;
|
||||
}
|
||||
accel_state->common_attributes.data_ready = false;
|
||||
atomic_set(&accel_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&accel_state->common_attributes);
|
||||
if (ret < 0) {
|
||||
|
439
drivers/iio/accel/mma8452.c
Normal file
439
drivers/iio/accel/mma8452.c
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer
|
||||
*
|
||||
* Copyright 2014 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.
|
||||
*
|
||||
* 7-bit I2C slave address 0x1c/0x1d (pin selectable)
|
||||
*
|
||||
* TODO: interrupt, thresholding, orientation / freefall events, autosleep
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#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 MMA8452_STATUS 0x00
|
||||
#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
|
||||
#define MMA8452_OUT_Y 0x03
|
||||
#define MMA8452_OUT_Z 0x05
|
||||
#define MMA8452_WHO_AM_I 0x0d
|
||||
#define MMA8452_DATA_CFG 0x0e
|
||||
#define MMA8452_OFF_X 0x2f
|
||||
#define MMA8452_OFF_Y 0x30
|
||||
#define MMA8452_OFF_Z 0x31
|
||||
#define MMA8452_CTRL_REG1 0x2a
|
||||
#define MMA8452_CTRL_REG2 0x2b
|
||||
|
||||
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
|
||||
|
||||
#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3))
|
||||
#define MMA8452_CTRL_DR_SHIFT 3
|
||||
#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
|
||||
#define MMA8452_CTRL_ACTIVE BIT(0)
|
||||
|
||||
#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0))
|
||||
#define MMA8452_DATA_CFG_FS_2G 0
|
||||
#define MMA8452_DATA_CFG_FS_4G 1
|
||||
#define MMA8452_DATA_CFG_FS_8G 2
|
||||
|
||||
#define MMA8452_DEVICE_ID 0x2a
|
||||
|
||||
struct mma8452_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
u8 ctrl_reg1;
|
||||
u8 data_cfg;
|
||||
};
|
||||
|
||||
static int mma8452_drdy(struct mma8452_data *data)
|
||||
{
|
||||
int tries = 150;
|
||||
|
||||
while (tries-- > 0) {
|
||||
int ret = i2c_smbus_read_byte_data(data->client,
|
||||
MMA8452_STATUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
|
||||
return 0;
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
dev_err(&data->client->dev, "data not ready\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
|
||||
{
|
||||
int ret = mma8452_drdy(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return i2c_smbus_read_i2c_block_data(data->client,
|
||||
MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf);
|
||||
}
|
||||
|
||||
static ssize_t mma8452_show_int_plus_micros(char *buf,
|
||||
const int (*vals)[2], int n)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
while (n-- > 0)
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"%d.%06d ", vals[n][0], vals[n][1]);
|
||||
|
||||
/* replace trailing space by newline */
|
||||
buf[len - 1] = '\n';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
|
||||
int val, int val2)
|
||||
{
|
||||
while (n-- > 0)
|
||||
if (val == vals[n][0] && val2 == vals[n][1])
|
||||
return n;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const int mma8452_samp_freq[8][2] = {
|
||||
{800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000},
|
||||
{6, 250000}, {1, 560000}
|
||||
};
|
||||
|
||||
static const int mma8452_scales[3][2] = {
|
||||
{0, 977}, {0, 1953}, {0, 3906}
|
||||
};
|
||||
|
||||
static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
|
||||
ARRAY_SIZE(mma8452_samp_freq));
|
||||
}
|
||||
|
||||
static ssize_t mma8452_show_scale_avail(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return mma8452_show_int_plus_micros(buf, mma8452_scales,
|
||||
ARRAY_SIZE(mma8452_scales));
|
||||
}
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
|
||||
static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
|
||||
mma8452_show_scale_avail, NULL, 0);
|
||||
|
||||
static int mma8452_get_samp_freq_index(struct mma8452_data *data,
|
||||
int val, int val2)
|
||||
{
|
||||
return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
|
||||
ARRAY_SIZE(mma8452_samp_freq), val, val2);
|
||||
}
|
||||
|
||||
static int mma8452_get_scale_index(struct mma8452_data *data,
|
||||
int val, int val2)
|
||||
{
|
||||
return mma8452_get_int_plus_micros_index(mma8452_scales,
|
||||
ARRAY_SIZE(mma8452_scales), val, val2);
|
||||
}
|
||||
|
||||
static int mma8452_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct mma8452_data *data = iio_priv(indio_dev);
|
||||
__be16 buffer[3];
|
||||
int i, ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = mma8452_read(data, buffer);
|
||||
mutex_unlock(&data->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = sign_extend32(
|
||||
be16_to_cpu(buffer[chan->scan_index]) >> 4, 11);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
|
||||
*val = mma8452_scales[i][0];
|
||||
*val2 = mma8452_scales[i][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
i = (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >>
|
||||
MMA8452_CTRL_DR_SHIFT;
|
||||
*val = mma8452_samp_freq[i][0];
|
||||
*val2 = mma8452_samp_freq[i][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X +
|
||||
chan->scan_index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = sign_extend32(ret, 7);
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mma8452_standby(struct mma8452_data *data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
|
||||
data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
|
||||
}
|
||||
|
||||
static int mma8452_active(struct mma8452_data *data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
|
||||
data->ctrl_reg1);
|
||||
}
|
||||
|
||||
static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
/* config can only be changed when in standby */
|
||||
ret = mma8452_standby(data);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, reg, val);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = mma8452_active(data);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mma8452_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct mma8452_data *data = iio_priv(indio_dev);
|
||||
int i;
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
i = mma8452_get_samp_freq_index(data, val, val2);
|
||||
if (i < 0)
|
||||
return -EINVAL;
|
||||
|
||||
data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
|
||||
data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
|
||||
return mma8452_change_config(data, MMA8452_CTRL_REG1,
|
||||
data->ctrl_reg1);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
i = mma8452_get_scale_index(data, val, val2);
|
||||
if (i < 0)
|
||||
return -EINVAL;
|
||||
data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
|
||||
data->data_cfg |= i;
|
||||
return mma8452_change_config(data, MMA8452_DATA_CFG,
|
||||
data->data_cfg);
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
if (val < -128 || val > 127)
|
||||
return -EINVAL;
|
||||
return mma8452_change_config(data, MMA8452_OFF_X +
|
||||
chan->scan_index, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t mma8452_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct mma8452_data *data = iio_priv(indio_dev);
|
||||
u8 buffer[16]; /* 3 16-bit channels + padding + ts */
|
||||
int ret;
|
||||
|
||||
ret = mma8452_read(data, (__be16 *) buffer);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
|
||||
iio_get_time_ns());
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define MMA8452_CHANNEL(axis, idx) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.scan_index = idx, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mma8452_channels[] = {
|
||||
MMA8452_CHANNEL(X, 0),
|
||||
MMA8452_CHANNEL(Y, 1),
|
||||
MMA8452_CHANNEL(Z, 2),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
static struct attribute *mma8452_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group mma8452_group = {
|
||||
.attrs = mma8452_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info mma8452_info = {
|
||||
.attrs = &mma8452_group,
|
||||
.read_raw = &mma8452_read_raw,
|
||||
.write_raw = &mma8452_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const unsigned long mma8452_scan_masks[] = {0x7, 0};
|
||||
|
||||
static int mma8452_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct mma8452_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != MMA8452_DEVICE_ID)
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
indio_dev->info = &mma8452_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = mma8452_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mma8452_channels);
|
||||
indio_dev->available_scan_masks = mma8452_scan_masks;
|
||||
|
||||
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
|
||||
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
|
||||
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
|
||||
data->ctrl_reg1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->data_cfg = MMA8452_DATA_CFG_FS_2G;
|
||||
ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
|
||||
data->data_cfg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
mma8452_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 mma8452_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);
|
||||
mma8452_standby(iio_priv(indio_dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mma8452_suspend(struct device *dev)
|
||||
{
|
||||
return mma8452_standby(iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev))));
|
||||
}
|
||||
|
||||
static int mma8452_resume(struct device *dev)
|
||||
{
|
||||
return mma8452_active(iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev))));
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
|
||||
#define MMA8452_PM_OPS (&mma8452_pm_ops)
|
||||
#else
|
||||
#define MMA8452_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id mma8452_id[] = {
|
||||
{ "mma8452", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mma8452_id);
|
||||
|
||||
static struct i2c_driver mma8452_driver = {
|
||||
.driver = {
|
||||
.name = "mma8452",
|
||||
.pm = MMA8452_PM_OPS,
|
||||
},
|
||||
.probe = mma8452_probe,
|
||||
.remove = mma8452_remove,
|
||||
.id_table = mma8452_id,
|
||||
};
|
||||
module_i2c_driver(mma8452_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
|
||||
MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -459,6 +459,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev,
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &accel_info;
|
||||
|
||||
st_sensors_power_enable(indio_dev);
|
||||
|
||||
err = st_sensors_check_device_support(indio_dev,
|
||||
ARRAY_SIZE(st_accel_sensors), st_accel_sensors);
|
||||
if (err < 0)
|
||||
@ -496,6 +498,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev,
|
||||
if (err)
|
||||
goto st_accel_device_register_error;
|
||||
|
||||
dev_info(&indio_dev->dev, "registered accelerometer %s\n",
|
||||
indio_dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
st_accel_device_register_error:
|
||||
@ -512,6 +517,8 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *adata = iio_priv(indio_dev);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (adata->get_irq_data_ready(indio_dev) > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
@ -96,9 +96,21 @@ config AD7923
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7923.
|
||||
|
||||
config AD799X
|
||||
tristate "Analog Devices AD799x ADC driver"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Analog Devices:
|
||||
ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998
|
||||
i2c analog to digital converters (ADC). Provides direct access
|
||||
via sysfs.
|
||||
|
||||
config AT91_ADC
|
||||
tristate "Atmel AT91 ADC"
|
||||
depends on ARCH_AT91
|
||||
depends on INPUT
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select SYSFS
|
||||
@ -107,7 +119,7 @@ config AT91_ADC
|
||||
|
||||
config EXYNOS_ADC
|
||||
tristate "Exynos ADC driver support"
|
||||
depends on OF
|
||||
depends on ARCH_EXYNOS || (OF && COMPILE_TEST)
|
||||
help
|
||||
Core support for the ADC block found in the Samsung EXYNOS series
|
||||
of SoCs for drivers such as the touchscreen and hwmon to use to share
|
||||
@ -146,11 +158,12 @@ config MCP320X
|
||||
called mcp320x.
|
||||
|
||||
config MCP3422
|
||||
tristate "Microchip Technology MCP3422/3/4 driver"
|
||||
tristate "Microchip Technology MCP3422/3/4/6/7/8 driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Microchip Technology's MCP3422,
|
||||
MCP3423 or MCP3424 analog to digital converters.
|
||||
Say yes here to build support for Microchip Technology's
|
||||
MCP3422, MCP3423, MCP3424, MCP3426, MCP3427 or MCP3428
|
||||
analog to digital converters.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called mcp3422.
|
||||
|
@ -11,6 +11,7 @@ obj-$(CONFIG_AD7476) += ad7476.o
|
||||
obj-$(CONFIG_AD7791) += ad7791.o
|
||||
obj-$(CONFIG_AD7793) += ad7793.o
|
||||
obj-$(CONFIG_AD7887) += ad7887.o
|
||||
obj-$(CONFIG_AD799X) += ad799x.o
|
||||
obj-$(CONFIG_AT91_ADC) += at91_adc.o
|
||||
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
|
||||
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
|
||||
|
@ -37,8 +37,144 @@
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#include "ad799x.h"
|
||||
#define AD799X_CHANNEL_SHIFT 4
|
||||
#define AD799X_STORAGEBITS 16
|
||||
/*
|
||||
* AD7991, AD7995 and AD7999 defines
|
||||
*/
|
||||
|
||||
#define AD7991_REF_SEL 0x08
|
||||
#define AD7991_FLTR 0x04
|
||||
#define AD7991_BIT_TRIAL_DELAY 0x02
|
||||
#define AD7991_SAMPLE_DELAY 0x01
|
||||
|
||||
/*
|
||||
* AD7992, AD7993, AD7994, AD7997 and AD7998 defines
|
||||
*/
|
||||
|
||||
#define AD7998_FLTR 0x08
|
||||
#define AD7998_ALERT_EN 0x04
|
||||
#define AD7998_BUSY_ALERT 0x02
|
||||
#define AD7998_BUSY_ALERT_POL 0x01
|
||||
|
||||
#define AD7998_CONV_RES_REG 0x0
|
||||
#define AD7998_ALERT_STAT_REG 0x1
|
||||
#define AD7998_CONF_REG 0x2
|
||||
#define AD7998_CYCLE_TMR_REG 0x3
|
||||
|
||||
#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
|
||||
#define AD7998_CYC_TCONF_32 0x1
|
||||
#define AD7998_CYC_TCONF_64 0x2
|
||||
#define AD7998_CYC_TCONF_128 0x3
|
||||
#define AD7998_CYC_TCONF_256 0x4
|
||||
#define AD7998_CYC_TCONF_512 0x5
|
||||
#define AD7998_CYC_TCONF_1024 0x6
|
||||
#define AD7998_CYC_TCONF_2048 0x7
|
||||
|
||||
#define AD7998_ALERT_STAT_CLEAR 0xFF
|
||||
|
||||
/*
|
||||
* AD7997 and AD7997 defines
|
||||
*/
|
||||
|
||||
#define AD7997_8_READ_SINGLE 0x80
|
||||
#define AD7997_8_READ_SEQUENCE 0x70
|
||||
/* TODO: move this into a common header */
|
||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||
|
||||
enum {
|
||||
ad7991,
|
||||
ad7995,
|
||||
ad7999,
|
||||
ad7992,
|
||||
ad7993,
|
||||
ad7994,
|
||||
ad7997,
|
||||
ad7998
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad799x_chip_info - chip specific information
|
||||
* @channel: channel specification
|
||||
* @num_channels: number of channels
|
||||
* @monitor_mode: whether the chip supports monitor interrupts
|
||||
* @default_config: device default configuration
|
||||
* @event_attrs: pointer to the monitor event attribute group
|
||||
*/
|
||||
struct ad799x_chip_info {
|
||||
struct iio_chan_spec channel[9];
|
||||
int num_channels;
|
||||
u16 default_config;
|
||||
const struct iio_info *info;
|
||||
};
|
||||
|
||||
struct ad799x_state {
|
||||
struct i2c_client *client;
|
||||
const struct ad799x_chip_info *chip_info;
|
||||
struct regulator *reg;
|
||||
struct regulator *vref;
|
||||
unsigned id;
|
||||
u16 config;
|
||||
|
||||
u8 *rx_buf;
|
||||
unsigned int transfer_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* ad799x_trigger_handler() bh of trigger launched polling to ring buffer
|
||||
*
|
||||
* Currently there is no option in this driver to disable the saving of
|
||||
* timestamps within the ring.
|
||||
**/
|
||||
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);
|
||||
int b_sent;
|
||||
u8 cmd;
|
||||
|
||||
switch (st->id) {
|
||||
case ad7991:
|
||||
case ad7995:
|
||||
case ad7999:
|
||||
cmd = st->config |
|
||||
(*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT);
|
||||
break;
|
||||
case ad7992:
|
||||
case ad7993:
|
||||
case ad7994:
|
||||
cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) |
|
||||
AD7998_CONV_RES_REG;
|
||||
break;
|
||||
case ad7997:
|
||||
case ad7998:
|
||||
cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG;
|
||||
break;
|
||||
default:
|
||||
cmd = 0;
|
||||
}
|
||||
|
||||
b_sent = i2c_smbus_read_i2c_block_data(st->client,
|
||||
cmd, st->transfer_size, st->rx_buf);
|
||||
if (b_sent < 0)
|
||||
goto out;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
|
||||
iio_get_time_ns());
|
||||
out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* ad799x register access by I2C
|
||||
@ -578,9 +714,10 @@ static int ad799x_probe(struct i2c_client *client,
|
||||
indio_dev->channels = st->chip_info->channel;
|
||||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
|
||||
ret = ad799x_register_ring_funcs_and_init(indio_dev);
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&ad799x_trigger_handler, NULL);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
goto error_disable_vref;
|
||||
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(&client->dev,
|
||||
@ -601,12 +738,11 @@ static int ad799x_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
|
||||
error_cleanup_ring:
|
||||
ad799x_ring_cleanup(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
error_disable_vref:
|
||||
regulator_disable(st->vref);
|
||||
error_disable_reg:
|
||||
if (!IS_ERR(st->vref))
|
||||
regulator_disable(st->vref);
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -618,11 +754,9 @@ static int ad799x_remove(struct i2c_client *client)
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
ad799x_ring_cleanup(indio_dev);
|
||||
if (!IS_ERR(st->vref))
|
||||
regulator_disable(st->vref);
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
regulator_disable(st->vref);
|
||||
regulator_disable(st->reg);
|
||||
kfree(st->rx_buf);
|
||||
|
||||
return 0;
|
@ -82,7 +82,7 @@ enum adc_version {
|
||||
#define ADC_CON_EN_START (1u << 0)
|
||||
#define ADC_DATX_MASK 0xFFF
|
||||
|
||||
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(1000))
|
||||
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
|
||||
|
||||
struct exynos_adc {
|
||||
void __iomem *regs;
|
||||
@ -112,6 +112,30 @@ static inline unsigned int exynos_adc_get_version(struct platform_device *pdev)
|
||||
return (unsigned int)match->data;
|
||||
}
|
||||
|
||||
static void exynos_adc_hw_init(struct exynos_adc *info)
|
||||
{
|
||||
u32 con1, con2;
|
||||
|
||||
if (info->version == ADC_V2) {
|
||||
con1 = ADC_V2_CON1_SOFT_RESET;
|
||||
writel(con1, ADC_V2_CON1(info->regs));
|
||||
|
||||
con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
|
||||
ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
|
||||
writel(con2, ADC_V2_CON2(info->regs));
|
||||
|
||||
/* Enable interrupts */
|
||||
writel(1, ADC_V2_INT_EN(info->regs));
|
||||
} else {
|
||||
/* set default prescaler values and Enable prescaler */
|
||||
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
|
||||
|
||||
/* Enable 12-bit ADC resolution */
|
||||
con1 |= ADC_V1_CON_RES;
|
||||
writel(con1, ADC_V1_CON(info->regs));
|
||||
}
|
||||
}
|
||||
|
||||
static int exynos_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
@ -121,11 +145,13 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
|
||||
struct exynos_adc *info = iio_priv(indio_dev);
|
||||
unsigned long timeout;
|
||||
u32 con1, con2;
|
||||
int ret;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_RAW)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
reinit_completion(&info->completion);
|
||||
|
||||
/* Select the channel to be used and Trigger conversion */
|
||||
if (info->version == ADC_V2) {
|
||||
@ -145,16 +171,21 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
|
||||
ADC_V1_CON(info->regs));
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_interruptible_timeout
|
||||
timeout = wait_for_completion_timeout
|
||||
(&info->completion, EXYNOS_ADC_TIMEOUT);
|
||||
*val = info->value;
|
||||
if (timeout == 0) {
|
||||
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
|
||||
exynos_adc_hw_init(info);
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
*val = info->value;
|
||||
*val2 = 0;
|
||||
ret = IIO_VAL_INT;
|
||||
}
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
if (timeout == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
|
||||
@ -226,30 +257,6 @@ static int exynos_adc_remove_devices(struct device *dev, void *c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_adc_hw_init(struct exynos_adc *info)
|
||||
{
|
||||
u32 con1, con2;
|
||||
|
||||
if (info->version == ADC_V2) {
|
||||
con1 = ADC_V2_CON1_SOFT_RESET;
|
||||
writel(con1, ADC_V2_CON1(info->regs));
|
||||
|
||||
con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
|
||||
ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
|
||||
writel(con2, ADC_V2_CON2(info->regs));
|
||||
|
||||
/* Enable interrupts */
|
||||
writel(1, ADC_V2_INT_EN(info->regs));
|
||||
} else {
|
||||
/* set default prescaler values and Enable prescaler */
|
||||
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
|
||||
|
||||
/* Enable 12-bit ADC resolution */
|
||||
con1 |= ADC_V1_CON_RES;
|
||||
writel(con1, ADC_V1_CON(info->regs));
|
||||
}
|
||||
}
|
||||
|
||||
static int exynos_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_adc *info = NULL;
|
||||
@ -290,32 +297,30 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
|
||||
init_completion(&info->completion);
|
||||
|
||||
ret = request_irq(info->irq, exynos_adc_isr,
|
||||
0, dev_name(&pdev->dev), info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
|
||||
info->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
writel(1, info->enable_reg);
|
||||
|
||||
info->clk = devm_clk_get(&pdev->dev, "adc");
|
||||
if (IS_ERR(info->clk)) {
|
||||
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
|
||||
PTR_ERR(info->clk));
|
||||
ret = PTR_ERR(info->clk);
|
||||
goto err_irq;
|
||||
return PTR_ERR(info->clk);
|
||||
}
|
||||
|
||||
info->vdd = devm_regulator_get(&pdev->dev, "vdd");
|
||||
if (IS_ERR(info->vdd)) {
|
||||
dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
|
||||
PTR_ERR(info->vdd));
|
||||
ret = PTR_ERR(info->vdd);
|
||||
goto err_irq;
|
||||
return PTR_ERR(info->vdd);
|
||||
}
|
||||
|
||||
ret = regulator_enable(info->vdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret)
|
||||
goto err_disable_reg;
|
||||
|
||||
writel(1, info->enable_reg);
|
||||
|
||||
info->version = exynos_adc_get_version(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
@ -332,16 +337,18 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
else
|
||||
indio_dev->num_channels = MAX_ADC_V2_CHANNELS;
|
||||
|
||||
ret = request_irq(info->irq, exynos_adc_isr,
|
||||
0, dev_name(&pdev->dev), info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
|
||||
info->irq);
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto err_irq;
|
||||
|
||||
ret = regulator_enable(info->vdd);
|
||||
if (ret)
|
||||
goto err_iio_dev;
|
||||
|
||||
clk_prepare_enable(info->clk);
|
||||
|
||||
exynos_adc_hw_init(info);
|
||||
|
||||
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
|
||||
@ -355,12 +362,14 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
err_of_populate:
|
||||
device_for_each_child(&indio_dev->dev, NULL,
|
||||
exynos_adc_remove_devices);
|
||||
regulator_disable(info->vdd);
|
||||
clk_disable_unprepare(info->clk);
|
||||
err_iio_dev:
|
||||
iio_device_unregister(indio_dev);
|
||||
err_irq:
|
||||
free_irq(info->irq, info);
|
||||
err_disable_clk:
|
||||
writel(0, info->enable_reg);
|
||||
clk_disable_unprepare(info->clk);
|
||||
err_disable_reg:
|
||||
regulator_disable(info->vdd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -371,11 +380,11 @@ static int exynos_adc_remove(struct platform_device *pdev)
|
||||
|
||||
device_for_each_child(&indio_dev->dev, NULL,
|
||||
exynos_adc_remove_devices);
|
||||
regulator_disable(info->vdd);
|
||||
clk_disable_unprepare(info->clk);
|
||||
writel(0, info->enable_reg);
|
||||
iio_device_unregister(indio_dev);
|
||||
free_irq(info->irq, info);
|
||||
writel(0, info->enable_reg);
|
||||
clk_disable_unprepare(info->clk);
|
||||
regulator_disable(info->vdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -397,8 +406,8 @@ static int exynos_adc_suspend(struct device *dev)
|
||||
writel(con, ADC_V1_CON(info->regs));
|
||||
}
|
||||
|
||||
clk_disable_unprepare(info->clk);
|
||||
writel(0, info->enable_reg);
|
||||
clk_disable_unprepare(info->clk);
|
||||
regulator_disable(info->vdd);
|
||||
|
||||
return 0;
|
||||
@ -414,9 +423,11 @@ static int exynos_adc_resume(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(1, info->enable_reg);
|
||||
clk_prepare_enable(info->clk);
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(1, info->enable_reg);
|
||||
exynos_adc_hw_init(info);
|
||||
|
||||
return 0;
|
||||
|
@ -1252,8 +1252,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
|
||||
.num_modes = ARRAY_SIZE(max1238_mode_list),
|
||||
.default_mode = s0to11,
|
||||
.info = &max1238_info,
|
||||
.channels = max1238_channels,
|
||||
.num_channels = ARRAY_SIZE(max1238_channels),
|
||||
.channels = max1038_channels,
|
||||
.num_channels = ARRAY_SIZE(max1038_channels),
|
||||
},
|
||||
[max11605] = {
|
||||
.bits = 8,
|
||||
@ -1262,8 +1262,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
|
||||
.num_modes = ARRAY_SIZE(max1238_mode_list),
|
||||
.default_mode = s0to11,
|
||||
.info = &max1238_info,
|
||||
.channels = max1238_channels,
|
||||
.num_channels = ARRAY_SIZE(max1238_channels),
|
||||
.channels = max1038_channels,
|
||||
.num_channels = ARRAY_SIZE(max1038_channels),
|
||||
},
|
||||
[max11606] = {
|
||||
.bits = 10,
|
||||
@ -1312,8 +1312,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
|
||||
.num_modes = ARRAY_SIZE(max1238_mode_list),
|
||||
.default_mode = s0to11,
|
||||
.info = &max1238_info,
|
||||
.channels = max1238_channels,
|
||||
.num_channels = ARRAY_SIZE(max1238_channels),
|
||||
.channels = max1138_channels,
|
||||
.num_channels = ARRAY_SIZE(max1138_channels),
|
||||
},
|
||||
[max11611] = {
|
||||
.bits = 10,
|
||||
@ -1322,8 +1322,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
|
||||
.num_modes = ARRAY_SIZE(max1238_mode_list),
|
||||
.default_mode = s0to11,
|
||||
.info = &max1238_info,
|
||||
.channels = max1238_channels,
|
||||
.num_channels = ARRAY_SIZE(max1238_channels),
|
||||
.channels = max1138_channels,
|
||||
.num_channels = ARRAY_SIZE(max1138_channels),
|
||||
},
|
||||
[max11612] = {
|
||||
.bits = 12,
|
||||
|
@ -1,10 +1,11 @@
|
||||
/*
|
||||
* mcp3422.c - driver for the Microchip mcp3422/3/4 chip family
|
||||
* mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family
|
||||
*
|
||||
* Copyright (C) 2013, Angelo Compagnucci
|
||||
* Author: Angelo Compagnucci <angelo.compagnucci@gmail.com>
|
||||
*
|
||||
* Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf
|
||||
* http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf
|
||||
*
|
||||
* This driver exports the value of analog input voltage to sysfs, the
|
||||
* voltage unit is nV.
|
||||
@ -96,6 +97,7 @@ static const int mcp3422_sign_extend[4] = {
|
||||
/* Client data (each client gets its own) */
|
||||
struct mcp3422 {
|
||||
struct i2c_client *i2c;
|
||||
u8 id;
|
||||
u8 config;
|
||||
u8 pga[4];
|
||||
struct mutex lock;
|
||||
@ -238,6 +240,8 @@ static int mcp3422_write_raw(struct iio_dev *iio,
|
||||
temp = MCP3422_SRATE_15;
|
||||
break;
|
||||
case 3:
|
||||
if (adc->id > 4)
|
||||
return -EINVAL;
|
||||
temp = MCP3422_SRATE_3;
|
||||
break;
|
||||
default:
|
||||
@ -271,6 +275,17 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t mcp3422_show_samp_freqs(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
|
||||
|
||||
if (adc->id > 4)
|
||||
return sprintf(buf, "240 60 15\n");
|
||||
|
||||
return sprintf(buf, "240 60 15 3\n");
|
||||
}
|
||||
|
||||
static ssize_t mcp3422_show_scales(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -284,12 +299,13 @@ static ssize_t mcp3422_show_scales(struct device *dev,
|
||||
mcp3422_scales[sample_rate][3]);
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("240 60 15 3");
|
||||
static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO,
|
||||
mcp3422_show_samp_freqs, NULL, 0);
|
||||
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_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
@ -335,6 +351,7 @@ static int mcp3422_probe(struct i2c_client *client,
|
||||
|
||||
adc = iio_priv(indio_dev);
|
||||
adc->i2c = client;
|
||||
adc->id = (u8)(id->driver_data);
|
||||
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
@ -343,13 +360,16 @@ static int mcp3422_probe(struct i2c_client *client,
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &mcp3422_info;
|
||||
|
||||
switch ((unsigned int)(id->driver_data)) {
|
||||
switch (adc->id) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 6:
|
||||
case 7:
|
||||
indio_dev->channels = mcp3422_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels);
|
||||
break;
|
||||
case 4:
|
||||
case 8:
|
||||
indio_dev->channels = mcp3424_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels);
|
||||
break;
|
||||
@ -375,6 +395,9 @@ static const struct i2c_device_id mcp3422_id[] = {
|
||||
{ "mcp3422", 2 },
|
||||
{ "mcp3423", 3 },
|
||||
{ "mcp3424", 4 },
|
||||
{ "mcp3426", 6 },
|
||||
{ "mcp3427", 7 },
|
||||
{ "mcp3428", 8 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mcp3422_id);
|
||||
@ -399,5 +422,5 @@ static struct i2c_driver mcp3422_driver = {
|
||||
module_i2c_driver(mcp3422_driver);
|
||||
|
||||
MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>");
|
||||
MODULE_DESCRIPTION("Microchip mcp3422/3/4 driver");
|
||||
MODULE_DESCRIPTION("Microchip mcp3422/3/4/6/7/8 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -26,6 +26,40 @@
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
struct {
|
||||
u32 usage_id;
|
||||
int unit; /* 0 for default others from HID sensor spec */
|
||||
int scale_val0; /* scale, whole number */
|
||||
int scale_val1; /* scale, fraction in micros */
|
||||
} static unit_conversion[] = {
|
||||
{HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650},
|
||||
{HID_USAGE_SENSOR_ACCEL_3D,
|
||||
HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0},
|
||||
{HID_USAGE_SENSOR_ACCEL_3D,
|
||||
HID_USAGE_SENSOR_UNITS_G, 9, 806650},
|
||||
|
||||
{HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453},
|
||||
{HID_USAGE_SENSOR_GYRO_3D,
|
||||
HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0},
|
||||
{HID_USAGE_SENSOR_GYRO_3D,
|
||||
HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453},
|
||||
|
||||
{HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000},
|
||||
{HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0},
|
||||
|
||||
{HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453},
|
||||
{HID_USAGE_SENSOR_INCLINOMETER_3D,
|
||||
HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453},
|
||||
{HID_USAGE_SENSOR_INCLINOMETER_3D,
|
||||
HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0},
|
||||
|
||||
{HID_USAGE_SENSOR_ALS, 0, 1, 0},
|
||||
{HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0},
|
||||
|
||||
{HID_USAGE_SENSOR_PRESSURE, 0, 100000, 0},
|
||||
{HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 1, 0},
|
||||
};
|
||||
|
||||
static int pow_10(unsigned power)
|
||||
{
|
||||
int i;
|
||||
@ -113,6 +147,26 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
|
||||
return value;
|
||||
}
|
||||
|
||||
s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
|
||||
{
|
||||
s32 value = 0;
|
||||
int ret;
|
||||
|
||||
ret = sensor_hub_get_feature(st->hsdev,
|
||||
st->poll.report_id,
|
||||
st->poll.index, &value);
|
||||
|
||||
if (ret < 0 || value < 0) {
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
|
||||
value = value * 1000;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL(hid_sensor_read_poll_value);
|
||||
|
||||
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
|
||||
int *val1, int *val2)
|
||||
{
|
||||
@ -209,15 +263,108 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
|
||||
}
|
||||
EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
|
||||
|
||||
/*
|
||||
* This fuction applies the unit exponent to the scale.
|
||||
* For example:
|
||||
* 9.806650 ->exp:2-> val0[980]val1[665000]
|
||||
* 9.000806 ->exp:2-> val0[900]val1[80600]
|
||||
* 0.174535 ->exp:2-> val0[17]val1[453500]
|
||||
* 1.001745 ->exp:0-> val0[1]val1[1745]
|
||||
* 1.001745 ->exp:2-> val0[100]val1[174500]
|
||||
* 1.001745 ->exp:4-> val0[10017]val1[450000]
|
||||
* 9.806650 ->exp:-2-> val0[0]val1[98066]
|
||||
*/
|
||||
static void adjust_exponent_micro(int *val0, int *val1, int scale0,
|
||||
int scale1, int exp)
|
||||
{
|
||||
int i;
|
||||
int x;
|
||||
int res;
|
||||
int rem;
|
||||
|
||||
if (exp > 0) {
|
||||
*val0 = scale0 * pow_10(exp);
|
||||
res = 0;
|
||||
if (exp > 6) {
|
||||
*val1 = 0;
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < exp; ++i) {
|
||||
x = scale1 / pow_10(5 - i);
|
||||
res += (pow_10(exp - 1 - i) * x);
|
||||
scale1 = scale1 % pow_10(5 - i);
|
||||
}
|
||||
*val0 += res;
|
||||
*val1 = scale1 * pow_10(exp);
|
||||
} else if (exp < 0) {
|
||||
exp = abs(exp);
|
||||
if (exp > 6) {
|
||||
*val0 = *val1 = 0;
|
||||
return;
|
||||
}
|
||||
*val0 = scale0 / pow_10(exp);
|
||||
rem = scale0 % pow_10(exp);
|
||||
res = 0;
|
||||
for (i = 0; i < (6 - exp); ++i) {
|
||||
x = scale1 / pow_10(5 - i);
|
||||
res += (pow_10(5 - exp - i) * x);
|
||||
scale1 = scale1 % pow_10(5 - i);
|
||||
}
|
||||
*val1 = rem * pow_10(6 - exp) + res;
|
||||
} else {
|
||||
*val0 = scale0;
|
||||
*val1 = scale1;
|
||||
}
|
||||
}
|
||||
|
||||
int hid_sensor_format_scale(u32 usage_id,
|
||||
struct hid_sensor_hub_attribute_info *attr_info,
|
||||
int *val0, int *val1)
|
||||
{
|
||||
int i;
|
||||
int exp;
|
||||
|
||||
*val0 = 1;
|
||||
*val1 = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) {
|
||||
if (unit_conversion[i].usage_id == usage_id &&
|
||||
unit_conversion[i].unit == attr_info->units) {
|
||||
exp = hid_sensor_convert_exponent(
|
||||
attr_info->unit_expo);
|
||||
adjust_exponent_micro(val0, val1,
|
||||
unit_conversion[i].scale_val0,
|
||||
unit_conversion[i].scale_val1, exp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
EXPORT_SYMBOL(hid_sensor_format_scale);
|
||||
|
||||
int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
|
||||
u32 usage_id,
|
||||
struct hid_sensor_common *st)
|
||||
{
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_FEATURE_REPORT, usage_id,
|
||||
HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,
|
||||
&st->poll);
|
||||
/* Default unit of measure is milliseconds */
|
||||
if (st->poll.units == 0)
|
||||
st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
|
||||
u32 usage_id,
|
||||
struct hid_sensor_common *st)
|
||||
{
|
||||
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_FEATURE_REPORT, usage_id,
|
||||
HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,
|
||||
&st->poll);
|
||||
|
||||
hid_sensor_get_reporting_interval(hsdev, usage_id, st);
|
||||
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_FEATURE_REPORT, usage_id,
|
||||
|
@ -28,16 +28,17 @@
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include "hid-sensor-trigger.h"
|
||||
|
||||
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
|
||||
{
|
||||
struct hid_sensor_common *st = iio_trigger_get_drvdata(trig);
|
||||
int state_val;
|
||||
int report_val;
|
||||
|
||||
if (state) {
|
||||
if (sensor_hub_device_open(st->hsdev))
|
||||
return -EIO;
|
||||
|
||||
atomic_inc(&st->data_ready);
|
||||
|
||||
state_val = hid_sensor_get_usage_index(st->hsdev,
|
||||
st->power_state.report_id,
|
||||
st->power_state.index,
|
||||
@ -47,6 +48,8 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
st->report_state.index,
|
||||
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
|
||||
} else {
|
||||
if (!atomic_dec_and_test(&st->data_ready))
|
||||
return 0;
|
||||
sensor_hub_device_close(st->hsdev);
|
||||
state_val = hid_sensor_get_usage_index(st->hsdev,
|
||||
st->power_state.report_id,
|
||||
@ -57,7 +60,6 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
st->report_state.index,
|
||||
HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM);
|
||||
}
|
||||
st->data_ready = state;
|
||||
|
||||
if (state_val >= 0) {
|
||||
state_val += st->power_state.logical_minimum;
|
||||
@ -75,6 +77,13 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hid_sensor_power_state);
|
||||
|
||||
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
{
|
||||
return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state);
|
||||
}
|
||||
|
||||
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
|
||||
{
|
||||
|
@ -22,5 +22,6 @@
|
||||
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
|
||||
struct hid_sensor_common *attrb);
|
||||
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb);
|
||||
int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
|
||||
|
||||
#endif
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
@ -198,6 +199,42 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_set_axis_enable);
|
||||
|
||||
void st_sensors_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.parent, "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.parent, "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");
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_power_enable);
|
||||
|
||||
void st_sensors_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);
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_power_disable);
|
||||
|
||||
static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
|
||||
struct st_sensors_platform_data *pdata)
|
||||
{
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -42,6 +43,10 @@ struct gyro_3d_state {
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX];
|
||||
u32 gyro_val[GYRO_3D_CHANNEL_MAX];
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
int value_offset;
|
||||
};
|
||||
|
||||
static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = {
|
||||
@ -56,6 +61,7 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
|
||||
.type = IIO_ANGL_VEL,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_X,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -65,6 +71,7 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
|
||||
.type = IIO_ANGL_VEL,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_Y,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -74,6 +81,7 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
|
||||
.type = IIO_ANGL_VEL,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_Z,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -104,31 +112,42 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
|
||||
u32 address;
|
||||
int ret;
|
||||
int ret_type;
|
||||
s32 poll_value;
|
||||
|
||||
*val = 0;
|
||||
*val2 = 0;
|
||||
switch (mask) {
|
||||
case 0:
|
||||
poll_value = hid_sensor_read_poll_value(
|
||||
&gyro_state->common_attributes);
|
||||
if (poll_value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
hid_sensor_power_state(&gyro_state->common_attributes, true);
|
||||
msleep_interruptible(poll_value * 2);
|
||||
report_id = gyro_state->gyro[chan->scan_index].report_id;
|
||||
address = gyro_3d_addresses[chan->scan_index];
|
||||
if (report_id >= 0)
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
gyro_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_GYRO_3D, address,
|
||||
report_id);
|
||||
gyro_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_GYRO_3D, address,
|
||||
report_id);
|
||||
else {
|
||||
*val = 0;
|
||||
hid_sensor_power_state(&gyro_state->common_attributes,
|
||||
false);
|
||||
return -EINVAL;
|
||||
}
|
||||
hid_sensor_power_state(&gyro_state->common_attributes, false);
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = gyro_state->gyro[CHANNEL_SCAN_INDEX_X].units;
|
||||
ret_type = IIO_VAL_INT;
|
||||
*val = gyro_state->scale_pre_decml;
|
||||
*val2 = gyro_state->scale_post_decml;
|
||||
ret_type = gyro_state->scale_precision;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = hid_sensor_convert_exponent(
|
||||
gyro_state->gyro[CHANNEL_SCAN_INDEX_X].unit_expo);
|
||||
*val = gyro_state->value_offset;
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
@ -197,9 +216,8 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "gyro_3d_proc_event [%d]\n",
|
||||
gyro_state->common_attributes.data_ready);
|
||||
if (gyro_state->common_attributes.data_ready)
|
||||
dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n");
|
||||
if (atomic_read(&gyro_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
gyro_state->gyro_val,
|
||||
sizeof(gyro_state->gyro_val));
|
||||
@ -262,6 +280,11 @@ static int gyro_3d_parse_report(struct platform_device *pdev,
|
||||
st->gyro[1].index, st->gyro[1].report_id,
|
||||
st->gyro[2].index, st->gyro[2].report_id);
|
||||
|
||||
st->scale_precision = hid_sensor_format_scale(
|
||||
HID_USAGE_SENSOR_GYRO_3D,
|
||||
&st->gyro[CHANNEL_SCAN_INDEX_X],
|
||||
&st->scale_pre_decml, &st->scale_post_decml);
|
||||
|
||||
/* Set Sensitivity field ids, when there is no individual modifier */
|
||||
if (st->common_attributes.sensitivity.index < 0) {
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
@ -330,7 +353,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
goto error_free_dev_mem;
|
||||
}
|
||||
gyro_state->common_attributes.data_ready = false;
|
||||
atomic_set(&gyro_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&gyro_state->common_attributes);
|
||||
if (ret < 0) {
|
||||
|
@ -110,8 +110,6 @@ static int itg3200_read_raw(struct iio_dev *indio_dev,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t itg3200_read_frequency(struct device *dev,
|
||||
|
@ -311,6 +311,8 @@ int st_gyro_common_probe(struct iio_dev *indio_dev,
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &gyro_info;
|
||||
|
||||
st_sensors_power_enable(indio_dev);
|
||||
|
||||
err = st_sensors_check_device_support(indio_dev,
|
||||
ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors);
|
||||
if (err < 0)
|
||||
@ -344,6 +346,9 @@ int st_gyro_common_probe(struct iio_dev *indio_dev,
|
||||
if (err)
|
||||
goto st_gyro_device_register_error;
|
||||
|
||||
dev_info(&indio_dev->dev, "registered gyroscope %s\n",
|
||||
indio_dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
st_gyro_device_register_error:
|
||||
@ -360,6 +365,8 @@ void st_gyro_common_remove(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *gdata = iio_priv(indio_dev);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (gdata->get_irq_data_ready(indio_dev) > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
@ -35,7 +35,7 @@ int __iio_add_chan_devattr(const char *postfix,
|
||||
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);
|
||||
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals);
|
||||
|
||||
/* Event interface flags */
|
||||
#define IIO_BUSY_BIT_POS 1
|
||||
|
@ -9,6 +9,8 @@ config INV_MPU6050_IIO
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
This driver supports the Invensense MPU6050 devices.
|
||||
This driver can also support MPU6500 in MPU6050 compatibility mode
|
||||
and also in MPU6500 mode with some limitations.
|
||||
It is a gyroscope/accelerometer combo device.
|
||||
This driver can be built as a module. The module will be called
|
||||
inv-mpu6050.
|
||||
|
@ -767,6 +767,7 @@ static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume);
|
||||
*/
|
||||
static const struct i2c_device_id inv_mpu_id[] = {
|
||||
{"mpu6050", INV_MPU6050},
|
||||
{"mpu6500", INV_MPU6500},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -59,6 +59,7 @@ struct inv_mpu6050_reg_map {
|
||||
/*device enum */
|
||||
enum inv_devices {
|
||||
INV_MPU6050,
|
||||
INV_MPU6500,
|
||||
INV_NUM_PARTS
|
||||
};
|
||||
|
||||
|
@ -150,7 +150,16 @@ static ssize_t iio_show_fixed_type(struct device *dev,
|
||||
type = IIO_BE;
|
||||
#endif
|
||||
}
|
||||
return sprintf(buf, "%s:%c%d/%d>>%u\n",
|
||||
if (this_attr->c->scan_type.repeat > 1)
|
||||
return sprintf(buf, "%s:%c%d/%dX%d>>%u\n",
|
||||
iio_endian_prefix[type],
|
||||
this_attr->c->scan_type.sign,
|
||||
this_attr->c->scan_type.realbits,
|
||||
this_attr->c->scan_type.storagebits,
|
||||
this_attr->c->scan_type.repeat,
|
||||
this_attr->c->scan_type.shift);
|
||||
else
|
||||
return sprintf(buf, "%s:%c%d/%d>>%u\n",
|
||||
iio_endian_prefix[type],
|
||||
this_attr->c->scan_type.sign,
|
||||
this_attr->c->scan_type.realbits,
|
||||
@ -475,14 +484,22 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
|
||||
for_each_set_bit(i, mask,
|
||||
indio_dev->masklength) {
|
||||
ch = iio_find_channel_from_si(indio_dev, i);
|
||||
length = ch->scan_type.storagebits / 8;
|
||||
if (ch->scan_type.repeat > 1)
|
||||
length = ch->scan_type.storagebits / 8 *
|
||||
ch->scan_type.repeat;
|
||||
else
|
||||
length = ch->scan_type.storagebits / 8;
|
||||
bytes = ALIGN(bytes, length);
|
||||
bytes += length;
|
||||
}
|
||||
if (timestamp) {
|
||||
ch = iio_find_channel_from_si(indio_dev,
|
||||
indio_dev->scan_index_timestamp);
|
||||
length = ch->scan_type.storagebits / 8;
|
||||
if (ch->scan_type.repeat > 1)
|
||||
length = ch->scan_type.storagebits / 8 *
|
||||
ch->scan_type.repeat;
|
||||
else
|
||||
length = ch->scan_type.storagebits / 8;
|
||||
bytes = ALIGN(bytes, length);
|
||||
bytes += length;
|
||||
}
|
||||
@ -959,7 +976,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
|
||||
indio_dev->masklength,
|
||||
in_ind + 1);
|
||||
ch = iio_find_channel_from_si(indio_dev, in_ind);
|
||||
length = ch->scan_type.storagebits/8;
|
||||
if (ch->scan_type.repeat > 1)
|
||||
length = ch->scan_type.storagebits / 8 *
|
||||
ch->scan_type.repeat;
|
||||
else
|
||||
length = ch->scan_type.storagebits / 8;
|
||||
/* Make sure we are aligned */
|
||||
in_loc += length;
|
||||
if (in_loc % length)
|
||||
@ -971,7 +992,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
|
||||
goto error_clear_mux_table;
|
||||
}
|
||||
ch = iio_find_channel_from_si(indio_dev, in_ind);
|
||||
length = ch->scan_type.storagebits/8;
|
||||
if (ch->scan_type.repeat > 1)
|
||||
length = ch->scan_type.storagebits / 8 *
|
||||
ch->scan_type.repeat;
|
||||
else
|
||||
length = ch->scan_type.storagebits / 8;
|
||||
if (out_loc % length)
|
||||
out_loc += length - out_loc % length;
|
||||
if (in_loc % length)
|
||||
@ -992,7 +1017,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
|
||||
}
|
||||
ch = iio_find_channel_from_si(indio_dev,
|
||||
indio_dev->scan_index_timestamp);
|
||||
length = ch->scan_type.storagebits/8;
|
||||
if (ch->scan_type.repeat > 1)
|
||||
length = ch->scan_type.storagebits / 8 *
|
||||
ch->scan_type.repeat;
|
||||
else
|
||||
length = ch->scan_type.storagebits / 8;
|
||||
if (out_loc % length)
|
||||
out_loc += length - out_loc % length;
|
||||
if (in_loc % length)
|
||||
|
@ -84,6 +84,9 @@ static const char * const iio_modifier_names[] = {
|
||||
[IIO_MOD_LIGHT_RED] = "red",
|
||||
[IIO_MOD_LIGHT_GREEN] = "green",
|
||||
[IIO_MOD_LIGHT_BLUE] = "blue",
|
||||
[IIO_MOD_QUATERNION] = "quaternion",
|
||||
[IIO_MOD_TEMP_AMBIENT] = "ambient",
|
||||
[IIO_MOD_TEMP_OBJECT] = "object",
|
||||
};
|
||||
|
||||
/* relies on pairs of these shared then separate */
|
||||
@ -340,7 +343,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev,
|
||||
else if (i >= e->num_items)
|
||||
return -EINVAL;
|
||||
|
||||
return sprintf(buf, "%s\n", e->items[i]);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_enum_read);
|
||||
|
||||
@ -373,41 +376,53 @@ EXPORT_SYMBOL_GPL(iio_enum_write);
|
||||
* @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.
|
||||
* @vals: pointer to the values, exact meaning depends on the type parameter.
|
||||
*/
|
||||
ssize_t iio_format_value(char *buf, unsigned int type, int val, int val2)
|
||||
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
|
||||
{
|
||||
unsigned long long tmp;
|
||||
bool scale_db = false;
|
||||
|
||||
switch (type) {
|
||||
case IIO_VAL_INT:
|
||||
return sprintf(buf, "%d\n", val);
|
||||
return sprintf(buf, "%d\n", vals[0]);
|
||||
case IIO_VAL_INT_PLUS_MICRO_DB:
|
||||
scale_db = true;
|
||||
case IIO_VAL_INT_PLUS_MICRO:
|
||||
if (val2 < 0)
|
||||
return sprintf(buf, "-%ld.%06u%s\n", abs(val), -val2,
|
||||
if (vals[1] < 0)
|
||||
return sprintf(buf, "-%ld.%06u%s\n", abs(vals[0]),
|
||||
-vals[1],
|
||||
scale_db ? " dB" : "");
|
||||
else
|
||||
return sprintf(buf, "%d.%06u%s\n", val, val2,
|
||||
return sprintf(buf, "%d.%06u%s\n", vals[0], vals[1],
|
||||
scale_db ? " dB" : "");
|
||||
case IIO_VAL_INT_PLUS_NANO:
|
||||
if (val2 < 0)
|
||||
return sprintf(buf, "-%ld.%09u\n", abs(val), -val2);
|
||||
if (vals[1] < 0)
|
||||
return sprintf(buf, "-%ld.%09u\n", abs(vals[0]),
|
||||
-vals[1]);
|
||||
else
|
||||
return sprintf(buf, "%d.%09u\n", val, val2);
|
||||
return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
|
||||
case IIO_VAL_FRACTIONAL:
|
||||
tmp = div_s64((s64)val * 1000000000LL, val2);
|
||||
val2 = do_div(tmp, 1000000000LL);
|
||||
val = tmp;
|
||||
return sprintf(buf, "%d.%09u\n", val, val2);
|
||||
tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
|
||||
vals[1] = do_div(tmp, 1000000000LL);
|
||||
vals[0] = tmp;
|
||||
return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
|
||||
case IIO_VAL_FRACTIONAL_LOG2:
|
||||
tmp = (s64)val * 1000000000LL >> val2;
|
||||
val2 = do_div(tmp, 1000000000LL);
|
||||
val = tmp;
|
||||
return sprintf(buf, "%d.%09u\n", val, val2);
|
||||
tmp = (s64)vals[0] * 1000000000LL >> vals[1];
|
||||
vals[1] = do_div(tmp, 1000000000LL);
|
||||
vals[0] = tmp;
|
||||
return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
|
||||
case IIO_VAL_INT_MULTIPLE:
|
||||
{
|
||||
int i;
|
||||
int len = 0;
|
||||
|
||||
for (i = 0; i < size; ++i)
|
||||
len += snprintf(&buf[len], PAGE_SIZE - len, "%d ",
|
||||
vals[i]);
|
||||
len += snprintf(&buf[len], PAGE_SIZE - len, "\n");
|
||||
return len;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -419,14 +434,23 @@ static ssize_t iio_read_channel_info(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, val2;
|
||||
int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
|
||||
&val, &val2, this_attr->address);
|
||||
int vals[INDIO_MAX_RAW_ELEMENTS];
|
||||
int ret;
|
||||
int val_len = 2;
|
||||
|
||||
if (indio_dev->info->read_raw_multi)
|
||||
ret = indio_dev->info->read_raw_multi(indio_dev, this_attr->c,
|
||||
INDIO_MAX_RAW_ELEMENTS,
|
||||
vals, &val_len,
|
||||
this_attr->address);
|
||||
else
|
||||
ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
|
||||
&vals[0], &vals[1], this_attr->address);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return iio_format_value(buf, ret, val, val2);
|
||||
return iio_format_value(buf, ret, val_len, vals);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -716,6 +740,8 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
|
||||
int i, ret, attrcount = 0;
|
||||
|
||||
for_each_set_bit(i, infomask, sizeof(infomask)*8) {
|
||||
if (i >= ARRAY_SIZE(iio_chan_info_postfix))
|
||||
return -EINVAL;
|
||||
ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
|
||||
chan,
|
||||
&iio_read_channel_info,
|
||||
@ -820,7 +846,7 @@ static ssize_t iio_show_dev_name(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
return sprintf(buf, "%s\n", indio_dev->name);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->name);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
|
||||
|
@ -270,7 +270,7 @@ 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, val2;
|
||||
int val, val2, val_arr[2];
|
||||
int ret;
|
||||
|
||||
ret = indio_dev->info->read_event_value(indio_dev,
|
||||
@ -279,7 +279,9 @@ static ssize_t iio_ev_value_show(struct device *dev,
|
||||
&val, &val2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return iio_format_value(buf, ret, val, val2);
|
||||
val_arr[0] = val;
|
||||
val_arr[1] = val2;
|
||||
return iio_format_value(buf, ret, 2, val_arr);
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_value_store(struct device *dev,
|
||||
@ -321,7 +323,9 @@ static int iio_device_add_event(struct iio_dev *indio_dev,
|
||||
char *postfix;
|
||||
int ret;
|
||||
|
||||
for_each_set_bit(i, mask, sizeof(*mask)) {
|
||||
for_each_set_bit(i, mask, sizeof(*mask)*8) {
|
||||
if (i >= ARRAY_SIZE(iio_ev_info_text))
|
||||
return -EINVAL;
|
||||
postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
|
||||
iio_ev_type_text[type], iio_ev_dir_text[dir],
|
||||
iio_ev_info_text[i]);
|
||||
|
@ -417,12 +417,24 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
|
||||
enum iio_chan_info_enum info)
|
||||
{
|
||||
int unused;
|
||||
int vals[INDIO_MAX_RAW_ELEMENTS];
|
||||
int ret;
|
||||
int val_len = 2;
|
||||
|
||||
if (val2 == NULL)
|
||||
val2 = &unused;
|
||||
|
||||
return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
|
||||
val, val2, info);
|
||||
if (chan->indio_dev->info->read_raw_multi) {
|
||||
ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev,
|
||||
chan->channel, INDIO_MAX_RAW_ELEMENTS,
|
||||
vals, &val_len, info);
|
||||
*val = vals[0];
|
||||
*val2 = vals[1];
|
||||
} else
|
||||
ret = chan->indio_dev->info->read_raw(chan->indio_dev,
|
||||
chan->channel, val, val2, info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iio_read_channel_raw(struct iio_channel *chan, int *val)
|
||||
@ -443,6 +455,24 @@ err_unlock:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_read_channel_raw);
|
||||
|
||||
int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chan->indio_dev->info_exist_lock);
|
||||
if (chan->indio_dev->info == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW);
|
||||
err_unlock:
|
||||
mutex_unlock(&chan->indio_dev->info_exist_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);
|
||||
|
||||
static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
|
||||
int raw, int *processed, unsigned int scale)
|
||||
{
|
||||
|
@ -5,13 +5,13 @@
|
||||
* IIO features supported by the driver:
|
||||
*
|
||||
* Read-only raw channels:
|
||||
* - illiminance_clear [lux]
|
||||
* - illiminance_ir
|
||||
* - illuminance_clear [lux]
|
||||
* - illuminance_ir
|
||||
* - proximity
|
||||
*
|
||||
* Triggered buffer:
|
||||
* - illiminance_clear
|
||||
* - illiminance_ir
|
||||
* - illuminance_clear
|
||||
* - illuminance_ir
|
||||
* - proximity
|
||||
*
|
||||
* Events:
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -37,6 +38,10 @@ struct als_state {
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info als_illum;
|
||||
u32 illum;
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
int value_offset;
|
||||
};
|
||||
|
||||
/* Channel definitions */
|
||||
@ -45,6 +50,7 @@ static const struct iio_chan_spec als_channels[] = {
|
||||
.type = IIO_INTENSITY,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_LIGHT_BOTH,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -75,6 +81,7 @@ static int als_read_raw(struct iio_dev *indio_dev,
|
||||
u32 address;
|
||||
int ret;
|
||||
int ret_type;
|
||||
s32 poll_value;
|
||||
|
||||
*val = 0;
|
||||
*val2 = 0;
|
||||
@ -90,24 +97,35 @@ static int als_read_raw(struct iio_dev *indio_dev,
|
||||
report_id = -1;
|
||||
break;
|
||||
}
|
||||
if (report_id >= 0)
|
||||
if (report_id >= 0) {
|
||||
poll_value = hid_sensor_read_poll_value(
|
||||
&als_state->common_attributes);
|
||||
if (poll_value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
hid_sensor_power_state(&als_state->common_attributes,
|
||||
true);
|
||||
msleep_interruptible(poll_value * 2);
|
||||
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
als_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_ALS, address,
|
||||
report_id);
|
||||
else {
|
||||
als_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_ALS, address,
|
||||
report_id);
|
||||
hid_sensor_power_state(&als_state->common_attributes,
|
||||
false);
|
||||
} else {
|
||||
*val = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = als_state->als_illum.units;
|
||||
ret_type = IIO_VAL_INT;
|
||||
*val = als_state->scale_pre_decml;
|
||||
*val2 = als_state->scale_post_decml;
|
||||
ret_type = als_state->scale_precision;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = hid_sensor_convert_exponent(
|
||||
als_state->als_illum.unit_expo);
|
||||
*val = als_state->value_offset;
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
@ -176,9 +194,8 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct als_state *als_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "als_proc_event [%d]\n",
|
||||
als_state->common_attributes.data_ready);
|
||||
if (als_state->common_attributes.data_ready)
|
||||
dev_dbg(&indio_dev->dev, "als_proc_event\n");
|
||||
if (atomic_read(&als_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
&als_state->illum,
|
||||
sizeof(als_state->illum));
|
||||
@ -229,6 +246,11 @@ static int als_parse_report(struct platform_device *pdev,
|
||||
dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
|
||||
st->als_illum.report_id);
|
||||
|
||||
st->scale_precision = hid_sensor_format_scale(
|
||||
HID_USAGE_SENSOR_ALS,
|
||||
&st->als_illum,
|
||||
&st->scale_pre_decml, &st->scale_post_decml);
|
||||
|
||||
/* Set Sensitivity field ids, when there is no individual modifier */
|
||||
if (st->common_attributes.sensitivity.index < 0) {
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
@ -296,7 +318,7 @@ static int hid_als_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
goto error_free_dev_mem;
|
||||
}
|
||||
als_state->common_attributes.data_ready = false;
|
||||
atomic_set(&als_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&als_state->common_attributes);
|
||||
if (ret < 0) {
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -75,6 +76,7 @@ static int prox_read_raw(struct iio_dev *indio_dev,
|
||||
u32 address;
|
||||
int ret;
|
||||
int ret_type;
|
||||
s32 poll_value;
|
||||
|
||||
*val = 0;
|
||||
*val2 = 0;
|
||||
@ -90,12 +92,24 @@ static int prox_read_raw(struct iio_dev *indio_dev,
|
||||
report_id = -1;
|
||||
break;
|
||||
}
|
||||
if (report_id >= 0)
|
||||
if (report_id >= 0) {
|
||||
poll_value = hid_sensor_read_poll_value(
|
||||
&prox_state->common_attributes);
|
||||
if (poll_value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
hid_sensor_power_state(&prox_state->common_attributes,
|
||||
true);
|
||||
|
||||
msleep_interruptible(poll_value * 2);
|
||||
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
prox_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_PROX, address,
|
||||
report_id);
|
||||
else {
|
||||
hid_sensor_power_state(&prox_state->common_attributes,
|
||||
false);
|
||||
} else {
|
||||
*val = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -176,9 +190,8 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct prox_state *prox_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "prox_proc_event [%d]\n",
|
||||
prox_state->common_attributes.data_ready);
|
||||
if (prox_state->common_attributes.data_ready)
|
||||
dev_dbg(&indio_dev->dev, "prox_proc_event\n");
|
||||
if (atomic_read(&prox_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
&prox_state->human_presence,
|
||||
sizeof(prox_state->human_presence));
|
||||
@ -297,7 +310,7 @@ static int hid_prox_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
goto error_free_dev_mem;
|
||||
}
|
||||
prox_state->common_attributes.data_ready = false;
|
||||
atomic_set(&prox_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&prox_state->common_attributes);
|
||||
if (ret) {
|
||||
|
@ -11,7 +11,8 @@ config AK8975
|
||||
depends on GPIOLIB
|
||||
help
|
||||
Say yes here to build support for Asahi Kasei AK8975 3-Axis
|
||||
Magnetometer.
|
||||
Magnetometer. This driver can also support AK8963, if i2c
|
||||
device name is identified as ak8963.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ak8975.
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -85,7 +86,14 @@
|
||||
#define AK8975_MAX_CONVERSION_TIMEOUT 500
|
||||
#define AK8975_CONVERSION_DONE_POLL_TIME 10
|
||||
#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000)
|
||||
#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256)
|
||||
#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
|
||||
#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
|
||||
|
||||
/* Compatible Asahi Kasei Compass parts */
|
||||
enum asahi_compass_chipset {
|
||||
AK8975,
|
||||
AK8963,
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-instance context data for the device.
|
||||
@ -101,6 +109,7 @@ struct ak8975_data {
|
||||
int eoc_irq;
|
||||
wait_queue_head_t data_ready_queue;
|
||||
unsigned long flags;
|
||||
enum asahi_compass_chipset chipset;
|
||||
};
|
||||
|
||||
static const int ak8975_index_to_reg[] = {
|
||||
@ -272,9 +281,21 @@ static int ak8975_setup(struct i2c_client *client)
|
||||
* Since ASA doesn't change, we cache the resultant scale factor into the
|
||||
* device context in ak8975_setup().
|
||||
*/
|
||||
data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]);
|
||||
data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]);
|
||||
data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]);
|
||||
if (data->chipset == AK8963) {
|
||||
/*
|
||||
* H range is +-8190 and magnetometer range is +-4912.
|
||||
* So HuT using the above explanation for 8975,
|
||||
* 4912/8190 = ~ 6/10.
|
||||
* So the Hadj should use 6/10 instead of 3/10.
|
||||
*/
|
||||
data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
|
||||
data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
|
||||
data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
|
||||
} else {
|
||||
data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
|
||||
data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
|
||||
data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -455,6 +476,27 @@ static const struct iio_info ak8975_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id ak_acpi_match[] = {
|
||||
{"AK8975", AK8975},
|
||||
{"AK8963", AK8963},
|
||||
{"INVN6500", AK8963},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
|
||||
|
||||
static char *ak8975_match_acpi_device(struct device *dev,
|
||||
enum asahi_compass_chipset *chipset)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
|
||||
id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!id)
|
||||
return NULL;
|
||||
*chipset = (int)id->driver_data;
|
||||
|
||||
return (char *)dev_name(dev);
|
||||
}
|
||||
|
||||
static int ak8975_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -462,6 +504,7 @@ static int ak8975_probe(struct i2c_client *client,
|
||||
struct iio_dev *indio_dev;
|
||||
int eoc_gpio;
|
||||
int err;
|
||||
char *name = NULL;
|
||||
|
||||
/* Grab and set up the supplied GPIO. */
|
||||
if (client->dev.platform_data)
|
||||
@ -499,6 +542,19 @@ static int ak8975_probe(struct i2c_client *client,
|
||||
data->eoc_gpio = eoc_gpio;
|
||||
data->eoc_irq = 0;
|
||||
|
||||
/* id will be NULL when enumerated via ACPI */
|
||||
if (id) {
|
||||
data->chipset =
|
||||
(enum asahi_compass_chipset)(id->driver_data);
|
||||
name = (char *) id->name;
|
||||
} else if (ACPI_HANDLE(&client->dev))
|
||||
name = ak8975_match_acpi_device(&client->dev, &data->chipset);
|
||||
else {
|
||||
err = -ENOSYS;
|
||||
goto exit_free_iio;
|
||||
}
|
||||
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
|
||||
|
||||
/* Perform some basic start-of-day setup of the device. */
|
||||
err = ak8975_setup(client);
|
||||
if (err < 0) {
|
||||
@ -513,9 +569,8 @@ static int ak8975_probe(struct i2c_client *client,
|
||||
indio_dev->channels = ak8975_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
|
||||
indio_dev->info = &ak8975_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
indio_dev->name = name;
|
||||
err = iio_device_register(indio_dev);
|
||||
if (err < 0)
|
||||
goto exit_free_iio;
|
||||
@ -552,7 +607,8 @@ static int ak8975_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ak8975_id[] = {
|
||||
{"ak8975", 0},
|
||||
{"ak8975", AK8975},
|
||||
{"ak8963", AK8963},
|
||||
{}
|
||||
};
|
||||
|
||||
@ -569,6 +625,7 @@ static struct i2c_driver ak8975_driver = {
|
||||
.driver = {
|
||||
.name = "ak8975",
|
||||
.of_match_table = ak8975_of_match,
|
||||
.acpi_match_table = ACPI_PTR(ak_acpi_match),
|
||||
},
|
||||
.probe = ak8975_probe,
|
||||
.remove = ak8975_remove,
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -42,6 +43,10 @@ struct magn_3d_state {
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
|
||||
u32 magn_val[MAGN_3D_CHANNEL_MAX];
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
int value_offset;
|
||||
};
|
||||
|
||||
static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
|
||||
@ -56,6 +61,7 @@ static const struct iio_chan_spec magn_3d_channels[] = {
|
||||
.type = IIO_MAGN,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_X,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -65,6 +71,7 @@ static const struct iio_chan_spec magn_3d_channels[] = {
|
||||
.type = IIO_MAGN,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_Y,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -74,6 +81,7 @@ static const struct iio_chan_spec magn_3d_channels[] = {
|
||||
.type = IIO_MAGN,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_Z,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
@ -104,11 +112,20 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
|
||||
u32 address;
|
||||
int ret;
|
||||
int ret_type;
|
||||
s32 poll_value;
|
||||
|
||||
*val = 0;
|
||||
*val2 = 0;
|
||||
switch (mask) {
|
||||
case 0:
|
||||
poll_value = hid_sensor_read_poll_value(
|
||||
&magn_state->common_attributes);
|
||||
if (poll_value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
hid_sensor_power_state(&magn_state->common_attributes, true);
|
||||
msleep_interruptible(poll_value * 2);
|
||||
|
||||
report_id =
|
||||
magn_state->magn[chan->scan_index].report_id;
|
||||
address = magn_3d_addresses[chan->scan_index];
|
||||
@ -119,17 +136,20 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
|
||||
report_id);
|
||||
else {
|
||||
*val = 0;
|
||||
hid_sensor_power_state(&magn_state->common_attributes,
|
||||
false);
|
||||
return -EINVAL;
|
||||
}
|
||||
hid_sensor_power_state(&magn_state->common_attributes, false);
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = magn_state->magn[CHANNEL_SCAN_INDEX_X].units;
|
||||
ret_type = IIO_VAL_INT;
|
||||
*val = magn_state->scale_pre_decml;
|
||||
*val2 = magn_state->scale_post_decml;
|
||||
ret_type = magn_state->scale_precision;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = hid_sensor_convert_exponent(
|
||||
magn_state->magn[CHANNEL_SCAN_INDEX_X].unit_expo);
|
||||
*val = magn_state->value_offset;
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
@ -198,9 +218,8 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct magn_3d_state *magn_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "magn_3d_proc_event [%d]\n",
|
||||
magn_state->common_attributes.data_ready);
|
||||
if (magn_state->common_attributes.data_ready)
|
||||
dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n");
|
||||
if (atomic_read(&magn_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
magn_state->magn_val,
|
||||
sizeof(magn_state->magn_val));
|
||||
@ -263,6 +282,11 @@ static int magn_3d_parse_report(struct platform_device *pdev,
|
||||
st->magn[1].index, st->magn[1].report_id,
|
||||
st->magn[2].index, st->magn[2].report_id);
|
||||
|
||||
st->scale_precision = hid_sensor_format_scale(
|
||||
HID_USAGE_SENSOR_COMPASS_3D,
|
||||
&st->magn[CHANNEL_SCAN_INDEX_X],
|
||||
&st->scale_pre_decml, &st->scale_post_decml);
|
||||
|
||||
/* Set Sensitivity field ids, when there is no individual modifier */
|
||||
if (st->common_attributes.sensitivity.index < 0) {
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
@ -334,7 +358,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
goto error_free_dev_mem;
|
||||
}
|
||||
magn_state->common_attributes.data_ready = false;
|
||||
atomic_set(&magn_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&magn_state->common_attributes);
|
||||
if (ret < 0) {
|
||||
|
@ -199,6 +199,13 @@ static int mag3110_read_raw(struct iio_dev *indio_dev,
|
||||
*val = mag3110_samp_freq[i][0];
|
||||
*val2 = mag3110_samp_freq[i][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
ret = i2c_smbus_read_word_swapped(data->client,
|
||||
MAG3110_OFF_X + 2 * chan->scan_index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = sign_extend32(ret >> 1, 14);
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -223,6 +230,11 @@ static int mag3110_write_raw(struct iio_dev *indio_dev,
|
||||
data->ctrl_reg1 |= rate << MAG3110_CTRL_DR_SHIFT;
|
||||
return i2c_smbus_write_byte_data(data->client,
|
||||
MAG3110_CTRL_REG1, data->ctrl_reg1);
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
if (val < -10000 || val > 10000)
|
||||
return -EINVAL;
|
||||
return i2c_smbus_write_word_swapped(data->client,
|
||||
MAG3110_OFF_X + 2 * chan->scan_index, val << 1);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -260,7 +272,8 @@ done:
|
||||
.type = IIO_MAGN, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.scan_index = idx, \
|
||||
@ -338,14 +351,14 @@ static int mag3110_probe(struct i2c_client *client,
|
||||
indio_dev->num_channels = ARRAY_SIZE(mag3110_channels);
|
||||
indio_dev->available_scan_masks = mag3110_scan_masks;
|
||||
|
||||
data->ctrl_reg1 = MAG3110_CTRL_DR_DEFAULT;
|
||||
data->ctrl_reg1 = MAG3110_CTRL_DR_DEFAULT << MAG3110_CTRL_DR_SHIFT;
|
||||
ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG1,
|
||||
data->ctrl_reg1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG2,
|
||||
MAG3110_CTRL_AUTO_MRST_EN | MAG3110_CTRL_RAW);
|
||||
MAG3110_CTRL_AUTO_MRST_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -355,6 +355,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev,
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &magn_info;
|
||||
|
||||
st_sensors_power_enable(indio_dev);
|
||||
|
||||
err = st_sensors_check_device_support(indio_dev,
|
||||
ARRAY_SIZE(st_magn_sensors), st_magn_sensors);
|
||||
if (err < 0)
|
||||
@ -387,6 +389,9 @@ int st_magn_common_probe(struct iio_dev *indio_dev,
|
||||
if (err)
|
||||
goto st_magn_device_register_error;
|
||||
|
||||
dev_info(&indio_dev->dev, "registered magnetometer %s\n",
|
||||
indio_dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
st_magn_device_register_error:
|
||||
@ -403,6 +408,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *mdata = iio_priv(indio_dev);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (mdata->get_irq_data_ready(indio_dev) > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
@ -16,4 +16,16 @@ config HID_SENSOR_INCLINOMETER_3D
|
||||
Say yes here to build support for the HID SENSOR
|
||||
Inclinometer 3D.
|
||||
|
||||
config HID_SENSOR_DEVICE_ROTATION
|
||||
depends on HID_SENSOR_HUB
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select HID_SENSOR_IIO_COMMON
|
||||
select HID_SENSOR_IIO_TRIGGER
|
||||
tristate "HID Device Rotation"
|
||||
help
|
||||
Say yes here to build support for the HID SENSOR
|
||||
device rotation. The output of a device rotation sensor
|
||||
is presented using quaternion format.
|
||||
|
||||
endmenu
|
||||
|
@ -4,3 +4,4 @@
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_HID_SENSOR_INCLINOMETER_3D) += hid-sensor-incl-3d.o
|
||||
obj-$(CONFIG_HID_SENSOR_DEVICE_ROTATION) += hid-sensor-rotation.o
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -42,6 +43,10 @@ struct incl_3d_state {
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX];
|
||||
u32 incl_val[INCLI_3D_CHANNEL_MAX];
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
int value_offset;
|
||||
};
|
||||
|
||||
static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = {
|
||||
@ -106,11 +111,20 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
|
||||
int report_id = -1;
|
||||
u32 address;
|
||||
int ret_type;
|
||||
s32 poll_value;
|
||||
|
||||
*val = 0;
|
||||
*val2 = 0;
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
poll_value = hid_sensor_read_poll_value(
|
||||
&incl_state->common_attributes);
|
||||
if (poll_value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
hid_sensor_power_state(&incl_state->common_attributes, true);
|
||||
msleep_interruptible(poll_value * 2);
|
||||
|
||||
report_id =
|
||||
incl_state->incl[chan->scan_index].report_id;
|
||||
address = incl_3d_addresses[chan->scan_index];
|
||||
@ -120,17 +134,20 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
|
||||
HID_USAGE_SENSOR_INCLINOMETER_3D, address,
|
||||
report_id);
|
||||
else {
|
||||
hid_sensor_power_state(&incl_state->common_attributes,
|
||||
false);
|
||||
return -EINVAL;
|
||||
}
|
||||
hid_sensor_power_state(&incl_state->common_attributes, false);
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = incl_state->incl[CHANNEL_SCAN_INDEX_X].units;
|
||||
ret_type = IIO_VAL_INT;
|
||||
*val = incl_state->scale_pre_decml;
|
||||
*val2 = incl_state->scale_post_decml;
|
||||
ret_type = incl_state->scale_precision;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = hid_sensor_convert_exponent(
|
||||
incl_state->incl[CHANNEL_SCAN_INDEX_X].unit_expo);
|
||||
*val = incl_state->value_offset;
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
@ -196,9 +213,8 @@ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct incl_3d_state *incl_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "incl_3d_proc_event [%d]\n",
|
||||
incl_state->common_attributes.data_ready);
|
||||
if (incl_state->common_attributes.data_ready)
|
||||
dev_dbg(&indio_dev->dev, "incl_3d_proc_event\n");
|
||||
if (atomic_read(&incl_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
(u8 *)incl_state->incl_val,
|
||||
sizeof(incl_state->incl_val));
|
||||
@ -279,6 +295,11 @@ static int incl_3d_parse_report(struct platform_device *pdev,
|
||||
st->incl[1].index, st->incl[1].report_id,
|
||||
st->incl[2].index, st->incl[2].report_id);
|
||||
|
||||
st->scale_precision = hid_sensor_format_scale(
|
||||
HID_USAGE_SENSOR_INCLINOMETER_3D,
|
||||
&st->incl[CHANNEL_SCAN_INDEX_X],
|
||||
&st->scale_pre_decml, &st->scale_post_decml);
|
||||
|
||||
/* Set Sensitivity field ids, when there is no individual modifier */
|
||||
if (st->common_attributes.sensitivity.index < 0) {
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
@ -349,7 +370,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
goto error_free_dev_mem;
|
||||
}
|
||||
incl_state->common_attributes.data_ready = false;
|
||||
atomic_set(&incl_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&incl_state->common_attributes);
|
||||
if (ret) {
|
||||
|
346
drivers/iio/orientation/hid-sensor-rotation.c
Normal file
346
drivers/iio/orientation/hid-sensor-rotation.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* HID Sensors Driver
|
||||
* Copyright (c) 2014, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include "../common/hid-sensors/hid-sensor-trigger.h"
|
||||
|
||||
struct dev_rot_state {
|
||||
struct hid_sensor_hub_callbacks callbacks;
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info quaternion;
|
||||
u32 sampled_vals[4];
|
||||
};
|
||||
|
||||
/* Channel definitions */
|
||||
static const struct iio_chan_spec dev_rot_channels[] = {
|
||||
{
|
||||
.type = IIO_ROT,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_QUATERNION,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS)
|
||||
}
|
||||
};
|
||||
|
||||
/* Adjust channel real bits based on report descriptor */
|
||||
static void dev_rot_adjust_channel_bit_mask(struct iio_chan_spec *chan,
|
||||
int size)
|
||||
{
|
||||
chan->scan_type.sign = 's';
|
||||
/* Real storage bits will change based on the report desc. */
|
||||
chan->scan_type.realbits = size * 8;
|
||||
/* Maximum size of a sample to capture is u32 */
|
||||
chan->scan_type.storagebits = sizeof(u32) * 8;
|
||||
chan->scan_type.repeat = 4;
|
||||
}
|
||||
|
||||
/* Channel read_raw handler */
|
||||
static int dev_rot_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int size, int *vals, int *val_len,
|
||||
long mask)
|
||||
{
|
||||
struct dev_rot_state *rot_state = iio_priv(indio_dev);
|
||||
int ret_type;
|
||||
int i;
|
||||
|
||||
vals[0] = 0;
|
||||
vals[1] = 0;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (size >= 4) {
|
||||
for (i = 0; i < 4; ++i)
|
||||
vals[i] = rot_state->sampled_vals[i];
|
||||
ret_type = IIO_VAL_INT_MULTIPLE;
|
||||
*val_len = 4;
|
||||
} else
|
||||
ret_type = -EINVAL;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret_type = hid_sensor_read_samp_freq_value(
|
||||
&rot_state->common_attributes, &vals[0], &vals[1]);
|
||||
break;
|
||||
case IIO_CHAN_INFO_HYSTERESIS:
|
||||
ret_type = hid_sensor_read_raw_hyst_value(
|
||||
&rot_state->common_attributes, &vals[0], &vals[1]);
|
||||
break;
|
||||
default:
|
||||
ret_type = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_type;
|
||||
}
|
||||
|
||||
/* Channel write_raw handler */
|
||||
static int dev_rot_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
int val2,
|
||||
long mask)
|
||||
{
|
||||
struct dev_rot_state *rot_state = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = hid_sensor_write_samp_freq_value(
|
||||
&rot_state->common_attributes, val, val2);
|
||||
break;
|
||||
case IIO_CHAN_INFO_HYSTERESIS:
|
||||
ret = hid_sensor_write_raw_hyst_value(
|
||||
&rot_state->common_attributes, val, val2);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_info dev_rot_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw_multi = &dev_rot_read_raw,
|
||||
.write_raw = &dev_rot_write_raw,
|
||||
};
|
||||
|
||||
/* Function to push data to buffer */
|
||||
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
|
||||
{
|
||||
dev_dbg(&indio_dev->dev, "hid_sensor_push_data >>\n");
|
||||
iio_push_to_buffers(indio_dev, (u8 *)data);
|
||||
dev_dbg(&indio_dev->dev, "hid_sensor_push_data <<\n");
|
||||
|
||||
}
|
||||
|
||||
/* Callback handler to send event after all samples are received and captured */
|
||||
static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
unsigned usage_id,
|
||||
void *priv)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct dev_rot_state *rot_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "dev_rot_proc_event\n");
|
||||
if (atomic_read(&rot_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
(u8 *)rot_state->sampled_vals,
|
||||
sizeof(rot_state->sampled_vals));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Capture samples in local storage */
|
||||
static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev,
|
||||
unsigned usage_id,
|
||||
size_t raw_len, char *raw_data,
|
||||
void *priv)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct dev_rot_state *rot_state = iio_priv(indio_dev);
|
||||
|
||||
if (usage_id == HID_USAGE_SENSOR_ORIENT_QUATERNION) {
|
||||
memcpy(rot_state->sampled_vals, raw_data,
|
||||
sizeof(rot_state->sampled_vals));
|
||||
dev_dbg(&indio_dev->dev, "Recd Quat len:%zu::%zu\n", raw_len,
|
||||
sizeof(rot_state->sampled_vals));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse report which is specific to an usage id*/
|
||||
static int dev_rot_parse_report(struct platform_device *pdev,
|
||||
struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_chan_spec *channels,
|
||||
unsigned usage_id,
|
||||
struct dev_rot_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_INPUT_REPORT,
|
||||
usage_id,
|
||||
HID_USAGE_SENSOR_ORIENT_QUATERNION,
|
||||
&st->quaternion);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_rot_adjust_channel_bit_mask(&channels[0],
|
||||
st->quaternion.size / 4);
|
||||
|
||||
dev_dbg(&pdev->dev, "dev_rot %x:%x\n", st->quaternion.index,
|
||||
st->quaternion.report_id);
|
||||
|
||||
dev_dbg(&pdev->dev, "dev_rot: attrib size %d\n",
|
||||
st->quaternion.size);
|
||||
|
||||
/* Set Sensitivity field ids, when there is no individual modifier */
|
||||
if (st->common_attributes.sensitivity.index < 0) {
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_FEATURE_REPORT, usage_id,
|
||||
HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
|
||||
HID_USAGE_SENSOR_DATA_ORIENTATION,
|
||||
&st->common_attributes.sensitivity);
|
||||
dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
|
||||
st->common_attributes.sensitivity.index,
|
||||
st->common_attributes.sensitivity.report_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function to initialize the processing for usage id */
|
||||
static int hid_dev_rot_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
static char *name = "dev_rotation";
|
||||
struct iio_dev *indio_dev;
|
||||
struct dev_rot_state *rot_state;
|
||||
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
|
||||
struct iio_chan_spec *channels;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev,
|
||||
sizeof(struct dev_rot_state));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
rot_state = iio_priv(indio_dev);
|
||||
rot_state->common_attributes.hsdev = hsdev;
|
||||
rot_state->common_attributes.pdev = pdev;
|
||||
|
||||
ret = hid_sensor_parse_common_attributes(hsdev,
|
||||
HID_USAGE_SENSOR_DEVICE_ORIENTATION,
|
||||
&rot_state->common_attributes);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup common attributes\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
channels = devm_kmemdup(&pdev->dev, dev_rot_channels,
|
||||
sizeof(dev_rot_channels), GFP_KERNEL);
|
||||
if (!channels) {
|
||||
dev_err(&pdev->dev, "failed to duplicate channels\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = dev_rot_parse_report(pdev, hsdev, channels,
|
||||
HID_USAGE_SENSOR_DEVICE_ORIENTATION, rot_state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup attributes\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->channels = channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(dev_rot_channels);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->info = &dev_rot_info;
|
||||
indio_dev->name = name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
return ret;
|
||||
}
|
||||
atomic_set(&rot_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&rot_state->common_attributes);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "trigger setup failed\n");
|
||||
goto error_unreg_buffer_funcs;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "device register failed\n");
|
||||
goto error_remove_trigger;
|
||||
}
|
||||
|
||||
rot_state->callbacks.send_event = dev_rot_proc_event;
|
||||
rot_state->callbacks.capture_sample = dev_rot_capture_sample;
|
||||
rot_state->callbacks.pdev = pdev;
|
||||
ret = sensor_hub_register_callback(hsdev,
|
||||
HID_USAGE_SENSOR_DEVICE_ORIENTATION,
|
||||
&rot_state->callbacks);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "callback reg failed\n");
|
||||
goto error_iio_unreg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_iio_unreg:
|
||||
iio_device_unregister(indio_dev);
|
||||
error_remove_trigger:
|
||||
hid_sensor_remove_trigger(&rot_state->common_attributes);
|
||||
error_unreg_buffer_funcs:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Function to deinitialize the processing for usage id */
|
||||
static int hid_dev_rot_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct dev_rot_state *rot_state = iio_priv(indio_dev);
|
||||
|
||||
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_DEVICE_ORIENTATION);
|
||||
iio_device_unregister(indio_dev);
|
||||
hid_sensor_remove_trigger(&rot_state->common_attributes);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id hid_dev_rot_ids[] = {
|
||||
{
|
||||
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
|
||||
.name = "HID-SENSOR-20008a",
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids);
|
||||
|
||||
static struct platform_driver hid_dev_rot_platform_driver = {
|
||||
.id_table = hid_dev_rot_ids,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = hid_dev_rot_probe,
|
||||
.remove = hid_dev_rot_remove,
|
||||
};
|
||||
module_platform_driver(hid_dev_rot_platform_driver);
|
||||
|
||||
MODULE_DESCRIPTION("HID Sensor Device Rotation");
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -19,6 +19,16 @@ config HID_SENSOR_PRESS
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called hid-sensor-press.
|
||||
|
||||
config MPL115
|
||||
tristate "Freescale MPL115A2 pressure sensor driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the Freescale MPL115A2
|
||||
pressure sensor connected via I2C.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mpl115.
|
||||
|
||||
config MPL3115
|
||||
tristate "Freescale MPL3115A2 pressure sensor driver"
|
||||
depends on I2C
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
|
||||
obj-$(CONFIG_MPL115) += mpl115.o
|
||||
obj-$(CONFIG_MPL3115) += mpl3115.o
|
||||
obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
|
||||
st_pressure-y := st_pressure_core.o
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -36,6 +37,10 @@ struct press_state {
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info press_attr;
|
||||
u32 press_data;
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
int value_offset;
|
||||
};
|
||||
|
||||
/* Channel definitions */
|
||||
@ -75,6 +80,7 @@ static int press_read_raw(struct iio_dev *indio_dev,
|
||||
u32 address;
|
||||
int ret;
|
||||
int ret_type;
|
||||
s32 poll_value;
|
||||
|
||||
*val = 0;
|
||||
*val2 = 0;
|
||||
@ -90,24 +96,35 @@ static int press_read_raw(struct iio_dev *indio_dev,
|
||||
report_id = -1;
|
||||
break;
|
||||
}
|
||||
if (report_id >= 0)
|
||||
if (report_id >= 0) {
|
||||
poll_value = hid_sensor_read_poll_value(
|
||||
&press_state->common_attributes);
|
||||
if (poll_value < 0)
|
||||
return -EINVAL;
|
||||
hid_sensor_power_state(&press_state->common_attributes,
|
||||
true);
|
||||
|
||||
msleep_interruptible(poll_value * 2);
|
||||
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
press_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_PRESSURE, address,
|
||||
report_id);
|
||||
else {
|
||||
hid_sensor_power_state(&press_state->common_attributes,
|
||||
false);
|
||||
} else {
|
||||
*val = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = press_state->press_attr.units;
|
||||
ret_type = IIO_VAL_INT;
|
||||
*val = press_state->scale_pre_decml;
|
||||
*val2 = press_state->scale_post_decml;
|
||||
ret_type = press_state->scale_precision;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = hid_sensor_convert_exponent(
|
||||
press_state->press_attr.unit_expo);
|
||||
*val = press_state->value_offset;
|
||||
ret_type = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
@ -176,9 +193,8 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct press_state *press_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "press_proc_event [%d]\n",
|
||||
press_state->common_attributes.data_ready);
|
||||
if (press_state->common_attributes.data_ready)
|
||||
dev_dbg(&indio_dev->dev, "press_proc_event\n");
|
||||
if (atomic_read(&press_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
&press_state->press_data,
|
||||
sizeof(press_state->press_data));
|
||||
@ -229,6 +245,11 @@ static int press_parse_report(struct platform_device *pdev,
|
||||
dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index,
|
||||
st->press_attr.report_id);
|
||||
|
||||
st->scale_precision = hid_sensor_format_scale(
|
||||
HID_USAGE_SENSOR_PRESSURE,
|
||||
&st->press_attr,
|
||||
&st->scale_pre_decml, &st->scale_post_decml);
|
||||
|
||||
/* Set Sensitivity field ids, when there is no individual modifier */
|
||||
if (st->common_attributes.sensitivity.index < 0) {
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
@ -298,7 +319,7 @@ static int hid_press_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
goto error_free_dev_mem;
|
||||
}
|
||||
press_state->common_attributes.data_ready = false;
|
||||
atomic_set(&press_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&press_state->common_attributes);
|
||||
if (ret) {
|
||||
|
211
drivers/iio/pressure/mpl115.c
Normal file
211
drivers/iio/pressure/mpl115.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* mpl115.c - Support for Freescale MPL115A2 pressure/temperature sensor
|
||||
*
|
||||
* Copyright (c) 2014 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.
|
||||
*
|
||||
* (7-bit I2C slave address 0x60)
|
||||
*
|
||||
* TODO: shutdown pin
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define MPL115_PADC 0x00 /* pressure ADC output value, MSB first, 10 bit */
|
||||
#define MPL115_TADC 0x02 /* temperature ADC output value, MSB first, 10 bit */
|
||||
#define MPL115_A0 0x04 /* 12 bit integer, 3 bit fraction */
|
||||
#define MPL115_B1 0x06 /* 2 bit integer, 13 bit fraction */
|
||||
#define MPL115_B2 0x08 /* 1 bit integer, 14 bit fraction */
|
||||
#define MPL115_C12 0x0a /* 0 bit integer, 13 bit fraction */
|
||||
#define MPL115_CONVERT 0x12 /* convert temperature and pressure */
|
||||
|
||||
struct mpl115_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
s16 a0;
|
||||
s16 b1, b2;
|
||||
s16 c12;
|
||||
};
|
||||
|
||||
static int mpl115_request(struct mpl115_data *data)
|
||||
{
|
||||
int ret = i2c_smbus_write_byte_data(data->client, MPL115_CONVERT, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
usleep_range(3000, 4000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpl115_comp_pressure(struct mpl115_data *data, int *val, int *val2)
|
||||
{
|
||||
int ret;
|
||||
u16 padc, tadc;
|
||||
int a1, y1, pcomp;
|
||||
unsigned kpa;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = mpl115_request(data);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(data->client, MPL115_PADC);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
padc = ret >> 6;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(data->client, MPL115_TADC);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
tadc = ret >> 6;
|
||||
|
||||
/* see Freescale AN3785 */
|
||||
a1 = data->b1 + ((data->c12 * tadc) >> 11);
|
||||
y1 = (data->a0 << 10) + a1 * padc;
|
||||
|
||||
/* compensated pressure with 4 fractional bits */
|
||||
pcomp = (y1 + ((data->b2 * (int) tadc) >> 1)) >> 9;
|
||||
|
||||
kpa = pcomp * (115 - 50) / 1023 + (50 << 4);
|
||||
*val = kpa >> 4;
|
||||
*val2 = (kpa & 15) * (1000000 >> 4);
|
||||
done:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mpl115_read_temp(struct mpl115_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = mpl115_request(data);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
ret = i2c_smbus_read_word_swapped(data->client, MPL115_TADC);
|
||||
done:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mpl115_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct mpl115_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
ret = mpl115_comp_pressure(data, val, val2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
/* temperature -5.35 C / LSB, 472 LSB is 25 C */
|
||||
ret = mpl115_read_temp(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret >> 6;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = 605;
|
||||
*val2 = 750000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = -186;
|
||||
*val2 = 915888;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mpl115_channels[] = {
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_info mpl115_info = {
|
||||
.read_raw = &mpl115_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int mpl115_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct mpl115_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
indio_dev->info = &mpl115_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = mpl115_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mpl115_channels);
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(data->client, MPL115_A0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->a0 = ret;
|
||||
ret = i2c_smbus_read_word_swapped(data->client, MPL115_B1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->b1 = ret;
|
||||
ret = i2c_smbus_read_word_swapped(data->client, MPL115_B2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->b2 = ret;
|
||||
ret = i2c_smbus_read_word_swapped(data->client, MPL115_C12);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->c12 = ret;
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mpl115_id[] = {
|
||||
{ "mpl115", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mpl115_id);
|
||||
|
||||
static struct i2c_driver mpl115_driver = {
|
||||
.driver = {
|
||||
.name = "mpl115",
|
||||
},
|
||||
.probe = mpl115_probe,
|
||||
.id_table = mpl115_id,
|
||||
};
|
||||
module_i2c_driver(mpl115_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
|
||||
MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -23,7 +23,6 @@
|
||||
#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>
|
||||
@ -387,40 +386,6 @@ 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)
|
||||
{
|
||||
@ -431,7 +396,7 @@ int st_press_common_probe(struct iio_dev *indio_dev,
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &press_info;
|
||||
|
||||
st_press_power_enable(indio_dev);
|
||||
st_sensors_power_enable(indio_dev);
|
||||
|
||||
err = st_sensors_check_device_support(indio_dev,
|
||||
ARRAY_SIZE(st_press_sensors),
|
||||
@ -474,6 +439,9 @@ int st_press_common_probe(struct iio_dev *indio_dev,
|
||||
if (err)
|
||||
goto st_press_device_register_error;
|
||||
|
||||
dev_info(&indio_dev->dev, "registered pressure sensor %s\n",
|
||||
indio_dev->name);
|
||||
|
||||
return err;
|
||||
|
||||
st_press_device_register_error:
|
||||
@ -490,7 +458,7 @@ 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);
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (pdata->get_irq_data_ready(indio_dev) > 0)
|
||||
|
19
drivers/iio/proximity/Kconfig
Normal file
19
drivers/iio/proximity/Kconfig
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Proximity sensors
|
||||
#
|
||||
|
||||
menu "Lightning sensors"
|
||||
|
||||
config AS3935
|
||||
tristate "AS3935 Franklin lightning sensor"
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
depends on SPI
|
||||
help
|
||||
Say Y here to build SPI interface support for the Austrian
|
||||
Microsystems AS3935 lightning detection sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called as3935
|
||||
|
||||
endmenu
|
6
drivers/iio/proximity/Makefile
Normal file
6
drivers/iio/proximity/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
#
|
||||
# Makefile for IIO proximity sensors
|
||||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AS3935) += as3935.o
|
456
drivers/iio/proximity/as3935.c
Normal file
456
drivers/iio/proximity/as3935.c
Normal file
@ -0,0 +1,456 @@
|
||||
/*
|
||||
* as3935.c - Support for AS3935 Franklin lightning sensor
|
||||
*
|
||||
* Copyright (C) 2014 Matt Ranostay <mranostay@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spi/spi.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/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
|
||||
#define AS3935_AFE_GAIN 0x00
|
||||
#define AS3935_AFE_MASK 0x3F
|
||||
#define AS3935_AFE_GAIN_MAX 0x1F
|
||||
#define AS3935_AFE_PWR_BIT BIT(0)
|
||||
|
||||
#define AS3935_INT 0x03
|
||||
#define AS3935_INT_MASK 0x07
|
||||
#define AS3935_EVENT_INT BIT(3)
|
||||
#define AS3935_NOISE_INT BIT(1)
|
||||
|
||||
#define AS3935_DATA 0x07
|
||||
#define AS3935_DATA_MASK 0x3F
|
||||
|
||||
#define AS3935_TUNE_CAP 0x08
|
||||
#define AS3935_CALIBRATE 0x3D
|
||||
|
||||
#define AS3935_WRITE_DATA BIT(15)
|
||||
#define AS3935_READ_DATA BIT(14)
|
||||
#define AS3935_ADDRESS(x) ((x) << 8)
|
||||
|
||||
#define MAX_PF_CAP 120
|
||||
#define TUNE_CAP_DIV 8
|
||||
|
||||
struct as3935_state {
|
||||
struct spi_device *spi;
|
||||
struct iio_trigger *trig;
|
||||
struct mutex lock;
|
||||
struct delayed_work work;
|
||||
|
||||
u32 tune_cap;
|
||||
u8 buf[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec as3935_channels[] = {
|
||||
{
|
||||
.type = IIO_PROXIMITY,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 6,
|
||||
.storagebits = 8,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
};
|
||||
|
||||
static int as3935_read(struct as3935_state *st, unsigned int reg, int *val)
|
||||
{
|
||||
u8 cmd;
|
||||
int ret;
|
||||
|
||||
cmd = (AS3935_READ_DATA | AS3935_ADDRESS(reg)) >> 8;
|
||||
ret = spi_w8r8(st->spi, cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int as3935_write(struct as3935_state *st,
|
||||
unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
u8 *buf = st->buf;
|
||||
|
||||
buf[0] = (AS3935_WRITE_DATA | AS3935_ADDRESS(reg)) >> 8;
|
||||
buf[1] = val;
|
||||
|
||||
return spi_write(st->spi, buf, 2);
|
||||
};
|
||||
|
||||
static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
|
||||
int val, ret;
|
||||
|
||||
ret = as3935_read(st, AS3935_AFE_GAIN, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
val = (val & AS3935_AFE_MASK) >> 1;
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
};
|
||||
|
||||
static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul((const char *) buf, 10, &val);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (val > AS3935_AFE_GAIN_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
as3935_write(st, AS3935_AFE_GAIN, val << 1);
|
||||
|
||||
return len;
|
||||
};
|
||||
|
||||
static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
|
||||
as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0);
|
||||
|
||||
|
||||
static struct attribute *as3935_attributes[] = {
|
||||
&iio_dev_attr_sensor_sensitivity.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group as3935_attribute_group = {
|
||||
.attrs = as3935_attributes,
|
||||
};
|
||||
|
||||
static int as3935_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
int *val2,
|
||||
long m)
|
||||
{
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
*val2 = 0;
|
||||
ret = as3935_read(st, AS3935_DATA, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (m == IIO_CHAN_INFO_RAW)
|
||||
return IIO_VAL_INT;
|
||||
|
||||
/* storm out of range */
|
||||
if (*val == AS3935_DATA_MASK)
|
||||
return -EINVAL;
|
||||
*val *= 1000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static const struct iio_info as3935_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.attrs = &as3935_attribute_group,
|
||||
.read_raw = &as3935_read_raw,
|
||||
};
|
||||
|
||||
static irqreturn_t as3935_trigger_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_poll_func *pf = private;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
int val, ret;
|
||||
|
||||
ret = as3935_read(st, AS3935_DATA, &val);
|
||||
if (ret)
|
||||
goto err_read;
|
||||
val &= AS3935_DATA_MASK;
|
||||
val *= 1000;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &val, pf->timestamp);
|
||||
err_read:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
};
|
||||
|
||||
static const struct iio_trigger_ops iio_interrupt_trigger_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void as3935_event_work(struct work_struct *work)
|
||||
{
|
||||
struct as3935_state *st;
|
||||
int val;
|
||||
|
||||
st = container_of(work, struct as3935_state, work.work);
|
||||
|
||||
as3935_read(st, AS3935_INT, &val);
|
||||
val &= AS3935_INT_MASK;
|
||||
|
||||
switch (val) {
|
||||
case AS3935_EVENT_INT:
|
||||
iio_trigger_poll(st->trig, iio_get_time_ns());
|
||||
break;
|
||||
case AS3935_NOISE_INT:
|
||||
dev_warn(&st->spi->dev, "noise level is too high");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
static irqreturn_t as3935_interrupt_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
|
||||
/*
|
||||
* Delay work for >2 milliseconds after an interrupt to allow
|
||||
* estimated distance to recalculated.
|
||||
*/
|
||||
|
||||
schedule_delayed_work(&st->work, msecs_to_jiffies(3));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void calibrate_as3935(struct as3935_state *st)
|
||||
{
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
/* mask disturber interrupt bit */
|
||||
as3935_write(st, AS3935_INT, BIT(5));
|
||||
|
||||
as3935_write(st, AS3935_CALIBRATE, 0x96);
|
||||
as3935_write(st, AS3935_TUNE_CAP,
|
||||
BIT(5) | (st->tune_cap / TUNE_CAP_DIV));
|
||||
|
||||
mdelay(2);
|
||||
as3935_write(st, AS3935_TUNE_CAP, (st->tune_cap / TUNE_CAP_DIV));
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int as3935_suspend(struct spi_device *spi, pm_message_t msg)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
int val, ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = as3935_read(st, AS3935_AFE_GAIN, &val);
|
||||
if (ret)
|
||||
goto err_suspend;
|
||||
val |= AS3935_AFE_PWR_BIT;
|
||||
|
||||
ret = as3935_write(st, AS3935_AFE_GAIN, val);
|
||||
|
||||
err_suspend:
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as3935_resume(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
int val, ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = as3935_read(st, AS3935_AFE_GAIN, &val);
|
||||
if (ret)
|
||||
goto err_resume;
|
||||
val &= ~AS3935_AFE_PWR_BIT;
|
||||
ret = as3935_write(st, AS3935_AFE_GAIN, val);
|
||||
|
||||
err_resume:
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#define as3935_suspend NULL
|
||||
#define as3935_resume NULL
|
||||
#endif
|
||||
|
||||
static int as3935_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct iio_trigger *trig;
|
||||
struct as3935_state *st;
|
||||
struct device_node *np = spi->dev.of_node;
|
||||
int ret;
|
||||
|
||||
/* Be sure lightning event interrupt is specified */
|
||||
if (!spi->irq) {
|
||||
dev_err(&spi->dev, "unable to get event interrupt\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
st->spi = spi;
|
||||
st->tune_cap = 0;
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
mutex_init(&st->lock);
|
||||
INIT_DELAYED_WORK(&st->work, as3935_event_work);
|
||||
|
||||
ret = of_property_read_u32(np,
|
||||
"ams,tuning-capacitor-pf", &st->tune_cap);
|
||||
if (ret) {
|
||||
st->tune_cap = 0;
|
||||
dev_warn(&spi->dev,
|
||||
"no tuning-capacitor-pf set, defaulting to %d",
|
||||
st->tune_cap);
|
||||
}
|
||||
|
||||
if (st->tune_cap > MAX_PF_CAP) {
|
||||
dev_err(&spi->dev,
|
||||
"wrong tuning-capacitor-pf setting of %d\n",
|
||||
st->tune_cap);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->channels = as3935_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(as3935_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &as3935_info;
|
||||
|
||||
trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
|
||||
indio_dev->name, indio_dev->id);
|
||||
|
||||
if (!trig)
|
||||
return -ENOMEM;
|
||||
|
||||
st->trig = trig;
|
||||
trig->dev.parent = indio_dev->dev.parent;
|
||||
iio_trigger_set_drvdata(trig, indio_dev);
|
||||
trig->ops = &iio_interrupt_trigger_ops;
|
||||
|
||||
ret = iio_trigger_register(trig);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "failed to register trigger\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&as3935_trigger_handler, NULL);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "cannot setup iio trigger\n");
|
||||
goto unregister_trigger;
|
||||
}
|
||||
|
||||
calibrate_as3935(st);
|
||||
|
||||
ret = devm_request_irq(&spi->dev, spi->irq,
|
||||
&as3935_interrupt_handler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
dev_name(&spi->dev),
|
||||
indio_dev);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "unable to request irq\n");
|
||||
goto unregister_buffer;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "unable to register device\n");
|
||||
goto unregister_buffer;
|
||||
}
|
||||
return 0;
|
||||
|
||||
unregister_buffer:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
unregister_trigger:
|
||||
iio_trigger_unregister(st->trig);
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
static int as3935_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct as3935_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
iio_trigger_unregister(st->trig);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static const struct spi_device_id as3935_id[] = {
|
||||
{"as3935", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, as3935_id);
|
||||
|
||||
static struct spi_driver as3935_driver = {
|
||||
.driver = {
|
||||
.name = "as3935",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = as3935_probe,
|
||||
.remove = as3935_remove,
|
||||
.id_table = as3935_id,
|
||||
.suspend = as3935_suspend,
|
||||
.resume = as3935_resume,
|
||||
};
|
||||
module_spi_driver(as3935_driver);
|
||||
|
||||
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
|
||||
MODULE_DESCRIPTION("AS3935 lightning sensor");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("spi:as3935");
|
@ -3,6 +3,16 @@
|
||||
#
|
||||
menu "Temperature sensors"
|
||||
|
||||
config MLX90614
|
||||
tristate "MLX90614 contact-less infrared sensor"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Melexis
|
||||
MLX90614 contact-less infrared sensor connected with I2C.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called mlx90614.
|
||||
|
||||
config TMP006
|
||||
tristate "TMP006 infrared thermopile sensor"
|
||||
depends on I2C
|
||||
|
@ -2,4 +2,5 @@
|
||||
# Makefile for industrial I/O temperature drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_MLX90614) += mlx90614.o
|
||||
obj-$(CONFIG_TMP006) += tmp006.o
|
||||
|
150
drivers/iio/temperature/mlx90614.c
Normal file
150
drivers/iio/temperature/mlx90614.c
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor
|
||||
*
|
||||
* Copyright (c) 2014 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.
|
||||
*
|
||||
* Driver for the Melexis MLX90614 I2C 16-bit IR thermopile sensor
|
||||
*
|
||||
* (7-bit I2C slave address 0x5a, 100KHz bus speed only!)
|
||||
*
|
||||
* TODO: sleep mode, configuration EEPROM
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#define MLX90614_OP_RAM 0x00
|
||||
|
||||
/* RAM offsets with 16-bit data, MSB first */
|
||||
#define MLX90614_TA 0x06 /* ambient temperature */
|
||||
#define MLX90614_TOBJ1 0x07 /* object temperature */
|
||||
|
||||
struct mlx90614_data {
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
||||
static int mlx90614_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *channel, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct mlx90614_data *data = iio_priv(indio_dev);
|
||||
s32 ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */
|
||||
switch (channel->channel2) {
|
||||
case IIO_MOD_TEMP_AMBIENT:
|
||||
ret = i2c_smbus_read_word_data(data->client,
|
||||
MLX90614_OP_RAM | MLX90614_TA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case IIO_MOD_TEMP_OBJECT:
|
||||
ret = i2c_smbus_read_word_data(data->client,
|
||||
MLX90614_OP_RAM | MLX90614_TOBJ1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = 13657;
|
||||
*val2 = 500000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 20;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mlx90614_channels[] = {
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_TEMP_AMBIENT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_TEMP_OBJECT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_info mlx90614_info = {
|
||||
.read_raw = mlx90614_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int mlx90614_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct mlx90614_data *data;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &mlx90614_info;
|
||||
|
||||
indio_dev->channels = mlx90614_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mlx90614_channels);
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
}
|
||||
|
||||
static int mlx90614_remove(struct i2c_client *client)
|
||||
{
|
||||
iio_device_unregister(i2c_get_clientdata(client));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mlx90614_id[] = {
|
||||
{ "mlx90614", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mlx90614_id);
|
||||
|
||||
static struct i2c_driver mlx90614_driver = {
|
||||
.driver = {
|
||||
.name = "mlx90614",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = mlx90614_probe,
|
||||
.remove = mlx90614_remove,
|
||||
.id_table = mlx90614_id,
|
||||
};
|
||||
module_i2c_driver(mlx90614_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
|
||||
MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -56,6 +56,7 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/goldfish.h>
|
||||
|
||||
/*
|
||||
* IMPORTANT: The following constants must match the ones used and defined
|
||||
@ -66,8 +67,10 @@
|
||||
#define PIPE_REG_COMMAND 0x00 /* write: value = command */
|
||||
#define PIPE_REG_STATUS 0x04 /* read */
|
||||
#define PIPE_REG_CHANNEL 0x08 /* read/write: channel id */
|
||||
#define PIPE_REG_CHANNEL_HIGH 0x30 /* read/write: channel id */
|
||||
#define PIPE_REG_SIZE 0x0c /* read/write: buffer size */
|
||||
#define PIPE_REG_ADDRESS 0x10 /* write: physical address */
|
||||
#define PIPE_REG_ADDRESS_HIGH 0x34 /* write: physical address */
|
||||
#define PIPE_REG_WAKES 0x14 /* read: wake flags */
|
||||
#define PIPE_REG_PARAMS_ADDR_LOW 0x18 /* read/write: batch data address */
|
||||
#define PIPE_REG_PARAMS_ADDR_HIGH 0x1c /* read/write: batch data address */
|
||||
@ -109,9 +112,9 @@
|
||||
#define PIPE_WAKE_WRITE (1 << 2) /* pipe can now be written to */
|
||||
|
||||
struct access_params {
|
||||
u32 channel;
|
||||
unsigned long channel;
|
||||
u32 size;
|
||||
u32 address;
|
||||
unsigned long address;
|
||||
u32 cmd;
|
||||
u32 result;
|
||||
/* reserved for future extension */
|
||||
@ -149,13 +152,14 @@ enum {
|
||||
|
||||
|
||||
static u32 goldfish_cmd_status(struct goldfish_pipe *pipe, u32 cmd)
|
||||
{
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 status;
|
||||
struct goldfish_pipe_dev *dev = pipe->dev;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
writel((u32)pipe, dev->base + PIPE_REG_CHANNEL);
|
||||
gf_write64((u64)(unsigned long)pipe, dev->base + PIPE_REG_CHANNEL,
|
||||
dev->base + PIPE_REG_CHANNEL_HIGH);
|
||||
writel(cmd, dev->base + PIPE_REG_COMMAND);
|
||||
status = readl(dev->base + PIPE_REG_STATUS);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
@ -163,12 +167,13 @@ static u32 goldfish_cmd_status(struct goldfish_pipe *pipe, u32 cmd)
|
||||
}
|
||||
|
||||
static void goldfish_cmd(struct goldfish_pipe *pipe, u32 cmd)
|
||||
{
|
||||
{
|
||||
unsigned long flags;
|
||||
struct goldfish_pipe_dev *dev = pipe->dev;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
writel((u32)pipe, dev->base + PIPE_REG_CHANNEL);
|
||||
gf_write64((u64)(unsigned long)pipe, dev->base + PIPE_REG_CHANNEL,
|
||||
dev->base + PIPE_REG_CHANNEL_HIGH);
|
||||
writel(cmd, dev->base + PIPE_REG_COMMAND);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
}
|
||||
@ -322,9 +327,12 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
|
||||
spin_lock_irqsave(&dev->lock, irq_flags);
|
||||
if (access_with_param(dev, CMD_WRITE_BUFFER + cmd_offset,
|
||||
address, avail, pipe, &status)) {
|
||||
writel((u32)pipe, dev->base + PIPE_REG_CHANNEL);
|
||||
gf_write64((u64)(unsigned long)pipe,
|
||||
dev->base + PIPE_REG_CHANNEL,
|
||||
dev->base + PIPE_REG_CHANNEL_HIGH);
|
||||
writel(avail, dev->base + PIPE_REG_SIZE);
|
||||
writel(address, dev->base + PIPE_REG_ADDRESS);
|
||||
gf_write64(address, dev->base + PIPE_REG_ADDRESS,
|
||||
dev->base + PIPE_REG_ADDRESS_HIGH);
|
||||
writel(CMD_WRITE_BUFFER + cmd_offset,
|
||||
dev->base + PIPE_REG_COMMAND);
|
||||
status = readl(dev->base + PIPE_REG_STATUS);
|
||||
@ -447,7 +455,15 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
|
||||
/* First read the channel, 0 means the end of the list */
|
||||
struct goldfish_pipe *pipe;
|
||||
unsigned long wakes;
|
||||
unsigned long channel = readl(dev->base + PIPE_REG_CHANNEL);
|
||||
unsigned long channel = 0;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
channel = (u64)readl(dev->base + PIPE_REG_CHANNEL_HIGH) << 32;
|
||||
|
||||
if (channel == 0)
|
||||
break;
|
||||
#endif
|
||||
channel |= readl(dev->base + PIPE_REG_CHANNEL);
|
||||
|
||||
if (channel == 0)
|
||||
break;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define PDEV_BUS_IO_SIZE (0x14)
|
||||
#define PDEV_BUS_IRQ (0x18)
|
||||
#define PDEV_BUS_IRQ_COUNT (0x1c)
|
||||
#define PDEV_BUS_GET_NAME_HIGH (0x20)
|
||||
|
||||
struct pdev_bus_dev {
|
||||
struct list_head list;
|
||||
@ -129,7 +130,10 @@ static int goldfish_new_pdev(void)
|
||||
dev->pdev.dev.dma_mask = (void *)(dev->pdev.name + name_len + 1);
|
||||
*dev->pdev.dev.dma_mask = ~0;
|
||||
|
||||
writel((unsigned long)name, pdev_bus_base + PDEV_BUS_GET_NAME);
|
||||
#ifdef CONFIG_64BIT
|
||||
writel((u32)((u64)name>>32), pdev_bus_base + PDEV_BUS_GET_NAME_HIGH);
|
||||
#endif
|
||||
writel((u32)(unsigned long)name, pdev_bus_base + PDEV_BUS_GET_NAME);
|
||||
name[name_len] = '\0';
|
||||
dev->pdev.id = readl(pdev_bus_base + PDEV_BUS_ID);
|
||||
dev->pdev.resource[0].start = base;
|
||||
@ -184,11 +188,6 @@ static int goldfish_pdev_bus_probe(struct platform_device *pdev)
|
||||
pdev_bus_addr = r->start;
|
||||
pdev_bus_len = resource_size(r);
|
||||
|
||||
if (request_mem_region(pdev_bus_addr, pdev_bus_len, "goldfish")) {
|
||||
dev_err(&pdev->dev, "unable to reserve Goldfish MMIO.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pdev_bus_base = ioremap(pdev_bus_addr, pdev_bus_len);
|
||||
if (pdev_bus_base == NULL) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -48,12 +48,12 @@ source "drivers/staging/rtl8712/Kconfig"
|
||||
|
||||
source "drivers/staging/rtl8188eu/Kconfig"
|
||||
|
||||
source "drivers/staging/rtl8192ee/Kconfig"
|
||||
|
||||
source "drivers/staging/rtl8723au/Kconfig"
|
||||
|
||||
source "drivers/staging/rtl8821ae/Kconfig"
|
||||
|
||||
source "drivers/staging/rts5139/Kconfig"
|
||||
|
||||
source "drivers/staging/rts5208/Kconfig"
|
||||
|
||||
source "drivers/staging/frontier/Kconfig"
|
||||
@ -90,8 +90,6 @@ source "drivers/staging/tidspbridge/Kconfig"
|
||||
|
||||
source "drivers/staging/quickstart/Kconfig"
|
||||
|
||||
source "drivers/staging/sbe-2t3e3/Kconfig"
|
||||
|
||||
source "drivers/staging/keucr/Kconfig"
|
||||
|
||||
source "drivers/staging/bcm/Kconfig"
|
||||
@ -144,6 +142,8 @@ source "drivers/staging/gs_fpgaboot/Kconfig"
|
||||
|
||||
source "drivers/staging/nokia_h4p/Kconfig"
|
||||
|
||||
source "drivers/staging/skein/Kconfig"
|
||||
|
||||
source "drivers/staging/unisys/Kconfig"
|
||||
|
||||
endif # STAGING
|
||||
|
@ -16,9 +16,9 @@ obj-$(CONFIG_RTL8192U) += rtl8192u/
|
||||
obj-$(CONFIG_RTL8192E) += rtl8192e/
|
||||
obj-$(CONFIG_R8712U) += rtl8712/
|
||||
obj-$(CONFIG_R8188EU) += rtl8188eu/
|
||||
obj-$(CONFIG_R8192EE) += rtl8192ee/
|
||||
obj-$(CONFIG_R8723AU) += rtl8723au/
|
||||
obj-$(CONFIG_R8821AE) += rtl8821ae/
|
||||
obj-$(CONFIG_RTS5139) += rts5139/
|
||||
obj-$(CONFIG_RTS5208) += rts5208/
|
||||
obj-$(CONFIG_TRANZPORT) += frontier/
|
||||
obj-$(CONFIG_IDE_PHISON) += phison/
|
||||
@ -39,7 +39,6 @@ obj-$(CONFIG_CXT1E1) += cxt1e1/
|
||||
obj-$(CONFIG_FB_XGI) += xgifb/
|
||||
obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/
|
||||
obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/
|
||||
obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3/
|
||||
obj-$(CONFIG_USB_ENESTORAGE) += keucr/
|
||||
obj-$(CONFIG_BCM_WIMAX) += bcm/
|
||||
obj-$(CONFIG_FT1000) += ft1000/
|
||||
@ -64,4 +63,5 @@ obj-$(CONFIG_DGAP) += dgap/
|
||||
obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/
|
||||
obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/
|
||||
obj-$(CONFIG_BT_NOKIA_H4P) += nokia_h4p/
|
||||
obj-$(CONFIG_CRYPTO_SKEIN) += skein/
|
||||
obj-$(CONFIG_UNISYSSPAR) += unisys/
|
||||
|
@ -329,6 +329,7 @@ static int alarm_release(struct inode *inode, struct file *file)
|
||||
if (file->private_data) {
|
||||
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
|
||||
uint32_t alarm_type_mask = 1U << i;
|
||||
|
||||
if (alarm_enabled & alarm_type_mask) {
|
||||
alarm_dbg(INFO,
|
||||
"%s: clear alarm, pending %d\n",
|
||||
|
@ -118,6 +118,7 @@ static int binder_set_stop_on_user_error(const char *val,
|
||||
struct kernel_param *kp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = param_set_int(val, kp);
|
||||
if (binder_stop_on_user_error < 2)
|
||||
wake_up(&binder_user_error_wait);
|
||||
@ -194,6 +195,7 @@ static struct binder_transaction_log_entry *binder_transaction_log_add(
|
||||
struct binder_transaction_log *log)
|
||||
{
|
||||
struct binder_transaction_log_entry *e;
|
||||
|
||||
e = &log->entry[log->next];
|
||||
memset(e, 0, sizeof(*e));
|
||||
log->next++;
|
||||
@ -432,6 +434,7 @@ static inline void binder_unlock(const char *tag)
|
||||
static void binder_set_nice(long nice)
|
||||
{
|
||||
long min_nice;
|
||||
|
||||
if (can_nice(current, nice)) {
|
||||
set_user_nice(current, nice);
|
||||
return;
|
||||
@ -584,6 +587,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
|
||||
for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
|
||||
int ret;
|
||||
struct page **page_array_ptr;
|
||||
|
||||
page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];
|
||||
|
||||
BUG_ON(*page);
|
||||
@ -726,6 +730,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
|
||||
binder_insert_allocated_buffer(proc, buffer);
|
||||
if (buffer_size != size) {
|
||||
struct binder_buffer *new_buffer = (void *)buffer->data + size;
|
||||
|
||||
list_add(&new_buffer->entry, &buffer->entry);
|
||||
new_buffer->free = 1;
|
||||
binder_insert_free_buffer(proc, new_buffer);
|
||||
@ -838,6 +843,7 @@ static void binder_free_buf(struct binder_proc *proc,
|
||||
if (!list_is_last(&buffer->entry, &proc->buffers)) {
|
||||
struct binder_buffer *next = list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry);
|
||||
|
||||
if (next->free) {
|
||||
rb_erase(&next->rb_node, &proc->free_buffers);
|
||||
binder_delete_free_buffer(proc, next);
|
||||
@ -846,6 +852,7 @@ static void binder_free_buf(struct binder_proc *proc,
|
||||
if (proc->buffers.next != &buffer->entry) {
|
||||
struct binder_buffer *prev = list_entry(buffer->entry.prev,
|
||||
struct binder_buffer, entry);
|
||||
|
||||
if (prev->free) {
|
||||
binder_delete_free_buffer(proc, buffer);
|
||||
rb_erase(&prev->rb_node, &proc->free_buffers);
|
||||
@ -1107,6 +1114,7 @@ static int binder_inc_ref(struct binder_ref *ref, int strong,
|
||||
struct list_head *target_list)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (strong) {
|
||||
if (ref->strong == 0) {
|
||||
ret = binder_inc_node(ref->node, 1, 1, target_list);
|
||||
@ -1138,6 +1146,7 @@ static int binder_dec_ref(struct binder_ref *ref, int strong)
|
||||
ref->strong--;
|
||||
if (ref->strong == 0) {
|
||||
int ret;
|
||||
|
||||
ret = binder_dec_node(ref->node, strong, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1177,6 +1186,7 @@ static void binder_send_failed_reply(struct binder_transaction *t,
|
||||
uint32_t error_code)
|
||||
{
|
||||
struct binder_thread *target_thread;
|
||||
|
||||
BUG_ON(t->flags & TF_ONE_WAY);
|
||||
while (1) {
|
||||
target_thread = t->from;
|
||||
@ -1247,6 +1257,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
|
||||
off_end = (void *)offp + buffer->offsets_size;
|
||||
for (; offp < off_end; offp++) {
|
||||
struct flat_binder_object *fp;
|
||||
|
||||
if (*offp > buffer->data_size - sizeof(*fp) ||
|
||||
buffer->data_size < sizeof(*fp) ||
|
||||
!IS_ALIGNED(*offp, sizeof(u32))) {
|
||||
@ -1259,6 +1270,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
|
||||
case BINDER_TYPE_BINDER:
|
||||
case BINDER_TYPE_WEAK_BINDER: {
|
||||
struct binder_node *node = binder_get_node(proc, fp->binder);
|
||||
|
||||
if (node == NULL) {
|
||||
pr_err("transaction release %d bad node %016llx\n",
|
||||
debug_id, (u64)fp->binder);
|
||||
@ -1272,6 +1284,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
|
||||
case BINDER_TYPE_HANDLE:
|
||||
case BINDER_TYPE_WEAK_HANDLE: {
|
||||
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
|
||||
|
||||
if (ref == NULL) {
|
||||
pr_err("transaction release %d bad handle %d\n",
|
||||
debug_id, fp->handle);
|
||||
@ -1363,6 +1376,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
} else {
|
||||
if (tr->target.handle) {
|
||||
struct binder_ref *ref;
|
||||
|
||||
ref = binder_get_ref(proc, tr->target.handle);
|
||||
if (ref == NULL) {
|
||||
binder_user_error("%d:%d got transaction to invalid handle\n",
|
||||
@ -1386,6 +1400,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
}
|
||||
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
|
||||
struct binder_transaction *tmp;
|
||||
|
||||
tmp = thread->transaction_stack;
|
||||
if (tmp->to_thread != thread) {
|
||||
binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n",
|
||||
@ -1452,7 +1467,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
t->from = thread;
|
||||
else
|
||||
t->from = NULL;
|
||||
t->sender_euid = proc->tsk->cred->euid;
|
||||
t->sender_euid = task_euid(proc->tsk);
|
||||
t->to_proc = target_proc;
|
||||
t->to_thread = target_thread;
|
||||
t->code = tr->code;
|
||||
@ -1501,6 +1516,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
off_end = (void *)offp + tr->offsets_size;
|
||||
for (; offp < off_end; offp++) {
|
||||
struct flat_binder_object *fp;
|
||||
|
||||
if (*offp > t->buffer->data_size - sizeof(*fp) ||
|
||||
t->buffer->data_size < sizeof(*fp) ||
|
||||
!IS_ALIGNED(*offp, sizeof(u32))) {
|
||||
@ -1515,6 +1531,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
case BINDER_TYPE_WEAK_BINDER: {
|
||||
struct binder_ref *ref;
|
||||
struct binder_node *node = binder_get_node(proc, fp->binder);
|
||||
|
||||
if (node == NULL) {
|
||||
node = binder_new_node(proc, fp->binder, fp->cookie);
|
||||
if (node == NULL) {
|
||||
@ -1529,6 +1546,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
proc->pid, thread->pid,
|
||||
(u64)fp->binder, node->debug_id,
|
||||
(u64)fp->cookie, (u64)node->cookie);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
goto err_binder_get_ref_for_node_failed;
|
||||
}
|
||||
ref = binder_get_ref_for_node(target_proc, node);
|
||||
@ -1553,6 +1571,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
case BINDER_TYPE_HANDLE:
|
||||
case BINDER_TYPE_WEAK_HANDLE: {
|
||||
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
|
||||
|
||||
if (ref == NULL) {
|
||||
binder_user_error("%d:%d got transaction with invalid handle, %d\n",
|
||||
proc->pid,
|
||||
@ -1575,6 +1594,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
(u64)ref->node->ptr);
|
||||
} else {
|
||||
struct binder_ref *new_ref;
|
||||
|
||||
new_ref = binder_get_ref_for_node(target_proc, ref->node);
|
||||
if (new_ref == NULL) {
|
||||
return_error = BR_FAILED_REPLY;
|
||||
@ -1694,6 +1714,7 @@ err_no_context_mgr_node:
|
||||
|
||||
{
|
||||
struct binder_transaction_log_entry *fe;
|
||||
|
||||
fe = binder_transaction_log_add(&binder_transaction_log_failed);
|
||||
*fe = *e;
|
||||
}
|
||||
@ -2024,12 +2045,14 @@ static int binder_thread_write(struct binder_proc *proc,
|
||||
struct binder_work *w;
|
||||
binder_uintptr_t cookie;
|
||||
struct binder_ref_death *death = NULL;
|
||||
|
||||
if (get_user(cookie, (binder_uintptr_t __user *)ptr))
|
||||
return -EFAULT;
|
||||
|
||||
ptr += sizeof(void *);
|
||||
list_for_each_entry(w, &proc->delivered_death, entry) {
|
||||
struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
|
||||
|
||||
if (tmp_death->cookie == cookie) {
|
||||
death = tmp_death;
|
||||
break;
|
||||
@ -2216,6 +2239,7 @@ retry:
|
||||
const char *cmd_name;
|
||||
int strong = node->internal_strong_refs || node->local_strong_refs;
|
||||
int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong;
|
||||
|
||||
if (weak && !node->has_weak_ref) {
|
||||
cmd = BR_INCREFS;
|
||||
cmd_name = "BR_INCREFS";
|
||||
@ -2322,6 +2346,7 @@ retry:
|
||||
BUG_ON(t->buffer == NULL);
|
||||
if (t->buffer->target_node) {
|
||||
struct binder_node *target_node = t->buffer->target_node;
|
||||
|
||||
tr.target.ptr = target_node->ptr;
|
||||
tr.cookie = target_node->cookie;
|
||||
t->saved_priority = task_nice(current);
|
||||
@ -2343,6 +2368,7 @@ retry:
|
||||
|
||||
if (t->from) {
|
||||
struct task_struct *sender = t->from->proc->tsk;
|
||||
|
||||
tr.sender_pid = task_tgid_nr_ns(sender,
|
||||
task_active_pid_ns(current));
|
||||
} else {
|
||||
@ -2413,6 +2439,7 @@ done:
|
||||
static void binder_release_work(struct list_head *list)
|
||||
{
|
||||
struct binder_work *w;
|
||||
|
||||
while (!list_empty(list)) {
|
||||
w = list_first_entry(list, struct binder_work, entry);
|
||||
list_del_init(&w->entry);
|
||||
@ -2574,6 +2601,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
struct binder_thread *thread;
|
||||
unsigned int size = _IOC_SIZE(cmd);
|
||||
void __user *ubuf = (void __user *)arg;
|
||||
kuid_t curr_euid = current_euid();
|
||||
|
||||
/*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/
|
||||
|
||||
@ -2593,6 +2621,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
switch (cmd) {
|
||||
case BINDER_WRITE_READ: {
|
||||
struct binder_write_read bwr;
|
||||
|
||||
if (size != sizeof(struct binder_write_read)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
@ -2658,15 +2687,16 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
goto err;
|
||||
}
|
||||
if (uid_valid(binder_context_mgr_uid)) {
|
||||
if (!uid_eq(binder_context_mgr_uid, current->cred->euid)) {
|
||||
if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
|
||||
from_kuid(&init_user_ns, current->cred->euid),
|
||||
from_kuid(&init_user_ns, curr_euid),
|
||||
from_kuid(&init_user_ns, binder_context_mgr_uid));
|
||||
ret = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
} else
|
||||
binder_context_mgr_uid = current->cred->euid;
|
||||
} else {
|
||||
binder_context_mgr_uid = curr_euid;
|
||||
}
|
||||
binder_context_mgr_node = binder_new_node(proc, 0, 0);
|
||||
if (binder_context_mgr_node == NULL) {
|
||||
ret = -ENOMEM;
|
||||
@ -2683,16 +2713,20 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
binder_free_thread(proc, thread);
|
||||
thread = NULL;
|
||||
break;
|
||||
case BINDER_VERSION:
|
||||
case BINDER_VERSION: {
|
||||
struct binder_version __user *ver = ubuf;
|
||||
|
||||
if (size != sizeof(struct binder_version)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
|
||||
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
|
||||
&ver->protocol_version)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
@ -2713,6 +2747,7 @@ err_unlocked:
|
||||
static void binder_vma_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct binder_proc *proc = vma->vm_private_data;
|
||||
|
||||
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
|
||||
"%d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n",
|
||||
proc->pid, vma->vm_start, vma->vm_end,
|
||||
@ -2723,6 +2758,7 @@ static void binder_vma_open(struct vm_area_struct *vma)
|
||||
static void binder_vma_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct binder_proc *proc = vma->vm_private_data;
|
||||
|
||||
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
|
||||
"%d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n",
|
||||
proc->pid, vma->vm_start, vma->vm_end,
|
||||
@ -2865,6 +2901,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
|
||||
|
||||
if (binder_debugfs_dir_entry_proc) {
|
||||
char strbuf[11];
|
||||
|
||||
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
|
||||
proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
|
||||
binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
|
||||
@ -2886,8 +2923,10 @@ static void binder_deferred_flush(struct binder_proc *proc)
|
||||
{
|
||||
struct rb_node *n;
|
||||
int wake_count = 0;
|
||||
|
||||
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) {
|
||||
struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node);
|
||||
|
||||
thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
|
||||
if (thread->looper & BINDER_LOOPER_STATE_WAITING) {
|
||||
wake_up_interruptible(&thread->wait);
|
||||
@ -2904,6 +2943,7 @@ static void binder_deferred_flush(struct binder_proc *proc)
|
||||
static int binder_release(struct inode *nodp, struct file *filp)
|
||||
{
|
||||
struct binder_proc *proc = filp->private_data;
|
||||
|
||||
debugfs_remove(proc->debugfs_entry);
|
||||
binder_defer_work(proc, BINDER_DEFERRED_RELEASE);
|
||||
|
||||
@ -3065,6 +3105,7 @@ static void binder_deferred_func(struct work_struct *work)
|
||||
struct files_struct *files;
|
||||
|
||||
int defer;
|
||||
|
||||
do {
|
||||
binder_lock(__func__);
|
||||
mutex_lock(&binder_deferred_lock);
|
||||
|
@ -408,6 +408,7 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client,
|
||||
|
||||
while (n) {
|
||||
struct ion_handle *entry = rb_entry(n, struct ion_handle, node);
|
||||
|
||||
if (buffer < entry->buffer)
|
||||
n = n->rb_left;
|
||||
else if (buffer > entry->buffer)
|
||||
@ -626,6 +627,10 @@ static void ion_handle_kmap_put(struct ion_handle *handle)
|
||||
{
|
||||
struct ion_buffer *buffer = handle->buffer;
|
||||
|
||||
if (!handle->kmap_cnt) {
|
||||
WARN(1, "%s: Double unmap detected! bailing...\n", __func__);
|
||||
return;
|
||||
}
|
||||
handle->kmap_cnt--;
|
||||
if (!handle->kmap_cnt)
|
||||
ion_buffer_kmap_put(buffer);
|
||||
@ -720,9 +725,11 @@ static int ion_get_client_serial(const struct rb_root *root,
|
||||
{
|
||||
int serial = -1;
|
||||
struct rb_node *node;
|
||||
|
||||
for (node = rb_first(root); node; node = rb_next(node)) {
|
||||
struct ion_client *client = rb_entry(node, struct ion_client,
|
||||
node);
|
||||
|
||||
if (strcmp(client->name, name))
|
||||
continue;
|
||||
serial = max(serial, client->display_serial);
|
||||
@ -1035,12 +1042,14 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
|
||||
static void ion_dma_buf_release(struct dma_buf *dmabuf)
|
||||
{
|
||||
struct ion_buffer *buffer = dmabuf->priv;
|
||||
|
||||
ion_buffer_put(buffer);
|
||||
}
|
||||
|
||||
static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset)
|
||||
{
|
||||
struct ion_buffer *buffer = dmabuf->priv;
|
||||
|
||||
return buffer->vaddr + offset * PAGE_SIZE;
|
||||
}
|
||||
|
||||
@ -1292,6 +1301,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
case ION_IOC_IMPORT:
|
||||
{
|
||||
struct ion_handle *handle;
|
||||
|
||||
handle = ion_import_dma_buf(client, data.fd.fd);
|
||||
if (IS_ERR(handle))
|
||||
ret = PTR_ERR(handle);
|
||||
@ -1393,6 +1403,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
|
||||
struct ion_client *client = rb_entry(n, struct ion_client,
|
||||
node);
|
||||
size_t size = ion_debug_heap_total(client, heap->id);
|
||||
|
||||
if (!size)
|
||||
continue;
|
||||
if (client->task) {
|
||||
@ -1516,6 +1527,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
|
||||
|
||||
if (!debug_file) {
|
||||
char buf[256], *path;
|
||||
|
||||
path = dentry_path(dev->heaps_debug_root, buf, 256);
|
||||
pr_err("Failed to create heap debugfs at %s/%s\n",
|
||||
path, heap->name);
|
||||
@ -1531,6 +1543,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
|
||||
&debug_shrink_fops);
|
||||
if (!debug_file) {
|
||||
char buf[256], *path;
|
||||
|
||||
path = dentry_path(dev->heaps_debug_root, buf, 256);
|
||||
pr_err("Failed to create heap shrinker debugfs at %s/%s\n",
|
||||
path, debug_name);
|
||||
@ -1606,6 +1619,7 @@ void __init ion_reserve(struct ion_platform_data *data)
|
||||
|
||||
if (data->heaps[i].base == 0) {
|
||||
phys_addr_t paddr;
|
||||
|
||||
paddr = memblock_alloc_base(data->heaps[i].size,
|
||||
data->heaps[i].align,
|
||||
MEMBLOCK_ALLOC_ANYWHERE);
|
||||
|
@ -81,7 +81,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap,
|
||||
if (align > PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
if (!table)
|
||||
return -ENOMEM;
|
||||
ret = sg_alloc_table(table, 1, GFP_KERNEL);
|
||||
|
@ -55,7 +55,7 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap,
|
||||
if (allocated_size > chunk_heap->size - chunk_heap->allocated)
|
||||
return -ENOMEM;
|
||||
|
||||
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
if (!table)
|
||||
return -ENOMEM;
|
||||
ret = sg_alloc_table(table, num_chunks, GFP_KERNEL);
|
||||
|
@ -48,6 +48,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap,
|
||||
for_each_sg(table->sgl, sg, table->nents, i) {
|
||||
int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE;
|
||||
struct page *page = sg_page(sg);
|
||||
|
||||
BUG_ON(i >= npages);
|
||||
for (j = 0; j < npages_this_entry; j++)
|
||||
*(tmp++) = page++;
|
||||
@ -105,6 +106,7 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
|
||||
static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot)
|
||||
{
|
||||
void *addr = vm_map_ram(pages, num, -1, pgprot);
|
||||
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
memset(addr, 0, PAGE_SIZE * num);
|
||||
|
@ -21,13 +21,9 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/swap.h>
|
||||
#include "ion_priv.h"
|
||||
|
||||
struct ion_page_pool_item {
|
||||
struct page *page;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
|
||||
{
|
||||
struct page *page = alloc_pages(pool->gfp_mask, pool->order);
|
||||
@ -47,19 +43,12 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool,
|
||||
|
||||
static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
|
||||
{
|
||||
struct ion_page_pool_item *item;
|
||||
|
||||
item = kmalloc(sizeof(struct ion_page_pool_item), GFP_KERNEL);
|
||||
if (!item)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&pool->mutex);
|
||||
item->page = page;
|
||||
if (PageHighMem(page)) {
|
||||
list_add_tail(&item->list, &pool->high_items);
|
||||
list_add_tail(&page->lru, &pool->high_items);
|
||||
pool->high_count++;
|
||||
} else {
|
||||
list_add_tail(&item->list, &pool->low_items);
|
||||
list_add_tail(&page->lru, &pool->low_items);
|
||||
pool->low_count++;
|
||||
}
|
||||
mutex_unlock(&pool->mutex);
|
||||
@ -68,28 +57,23 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
|
||||
|
||||
static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
|
||||
{
|
||||
struct ion_page_pool_item *item;
|
||||
struct page *page;
|
||||
|
||||
if (high) {
|
||||
BUG_ON(!pool->high_count);
|
||||
item = list_first_entry(&pool->high_items,
|
||||
struct ion_page_pool_item, list);
|
||||
page = list_first_entry(&pool->high_items, struct page, lru);
|
||||
pool->high_count--;
|
||||
} else {
|
||||
BUG_ON(!pool->low_count);
|
||||
item = list_first_entry(&pool->low_items,
|
||||
struct ion_page_pool_item, list);
|
||||
page = list_first_entry(&pool->low_items, struct page, lru);
|
||||
pool->low_count--;
|
||||
}
|
||||
|
||||
list_del(&item->list);
|
||||
page = item->page;
|
||||
kfree(item);
|
||||
list_del(&page->lru);
|
||||
return page;
|
||||
}
|
||||
|
||||
void *ion_page_pool_alloc(struct ion_page_pool *pool)
|
||||
struct page *ion_page_pool_alloc(struct ion_page_pool *pool)
|
||||
{
|
||||
struct page *page = NULL;
|
||||
|
||||
@ -112,6 +96,8 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
|
||||
{
|
||||
int ret;
|
||||
|
||||
BUG_ON(pool->order != compound_order(page));
|
||||
|
||||
ret = ion_page_pool_add(pool, page);
|
||||
if (ret)
|
||||
ion_page_pool_free_pages(pool, page);
|
||||
@ -119,12 +105,12 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
|
||||
|
||||
static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
|
||||
{
|
||||
int total = 0;
|
||||
int count = pool->low_count;
|
||||
|
||||
total += high ? (pool->high_count + pool->low_count) *
|
||||
(1 << pool->order) :
|
||||
pool->low_count * (1 << pool->order);
|
||||
return total;
|
||||
if (high)
|
||||
count += pool->high_count;
|
||||
|
||||
return count << pool->order;
|
||||
}
|
||||
|
||||
int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
|
||||
@ -133,7 +119,10 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
|
||||
int freed;
|
||||
bool high;
|
||||
|
||||
high = !!(gfp_mask & __GFP_HIGHMEM);
|
||||
if (current_is_kswapd())
|
||||
high = 1;
|
||||
else
|
||||
high = !!(gfp_mask & __GFP_HIGHMEM);
|
||||
|
||||
if (nr_to_scan == 0)
|
||||
return ion_page_pool_total(pool, high);
|
||||
@ -167,7 +156,7 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
|
||||
pool->low_count = 0;
|
||||
INIT_LIST_HEAD(&pool->low_items);
|
||||
INIT_LIST_HEAD(&pool->high_items);
|
||||
pool->gfp_mask = gfp_mask;
|
||||
pool->gfp_mask = gfp_mask | __GFP_COMP;
|
||||
pool->order = order;
|
||||
mutex_init(&pool->mutex);
|
||||
plist_node_init(&pool->list, order);
|
||||
|
@ -178,6 +178,7 @@ struct ion_heap {
|
||||
spinlock_t free_lock;
|
||||
wait_queue_head_t waitqueue;
|
||||
struct task_struct *task;
|
||||
|
||||
int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
|
||||
};
|
||||
|
||||
@ -377,7 +378,7 @@ struct ion_page_pool {
|
||||
|
||||
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
|
||||
void ion_page_pool_destroy(struct ion_page_pool *);
|
||||
void *ion_page_pool_alloc(struct ion_page_pool *);
|
||||
struct page *ion_page_pool_alloc(struct ion_page_pool *);
|
||||
void ion_page_pool_free(struct ion_page_pool *, struct page *);
|
||||
|
||||
/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
|
||||
|
@ -34,6 +34,7 @@ static const int num_orders = ARRAY_SIZE(orders);
|
||||
static int order_to_index(unsigned int order)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_orders; i++)
|
||||
if (order == orders[i])
|
||||
return i;
|
||||
@ -41,7 +42,7 @@ static int order_to_index(unsigned int order)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned int order_to_size(int order)
|
||||
static inline unsigned int order_to_size(int order)
|
||||
{
|
||||
return PAGE_SIZE << order;
|
||||
}
|
||||
@ -72,14 +73,12 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
|
||||
|
||||
if (order > 4)
|
||||
gfp_flags = high_order_gfp_flags;
|
||||
page = alloc_pages(gfp_flags, order);
|
||||
page = alloc_pages(gfp_flags | __GFP_COMP, order);
|
||||
if (!page)
|
||||
return NULL;
|
||||
ion_pages_sync_for_device(NULL, page, PAGE_SIZE << order,
|
||||
DMA_BIDIRECTIONAL);
|
||||
}
|
||||
if (!page)
|
||||
return NULL;
|
||||
|
||||
return page;
|
||||
}
|
||||
@ -92,6 +91,7 @@ static void free_buffer_page(struct ion_system_heap *heap,
|
||||
|
||||
if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) {
|
||||
struct ion_page_pool *pool = heap->pools[order_to_index(order)];
|
||||
|
||||
ion_page_pool_free(pool, page);
|
||||
} else {
|
||||
__free_pages(page, order);
|
||||
@ -124,7 +124,6 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
|
||||
|
||||
info->page = page;
|
||||
info->order = orders[i];
|
||||
INIT_LIST_HEAD(&info->list);
|
||||
return info;
|
||||
}
|
||||
kfree(info);
|
||||
@ -142,7 +141,6 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
|
||||
heap);
|
||||
struct sg_table *table;
|
||||
struct scatterlist *sg;
|
||||
int ret;
|
||||
struct list_head pages;
|
||||
struct page_info *info, *tmp_info;
|
||||
int i = 0;
|
||||
@ -160,24 +158,23 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
|
||||
info = alloc_largest_available(sys_heap, buffer, size_remaining,
|
||||
max_order);
|
||||
if (!info)
|
||||
goto err;
|
||||
goto free_pages;
|
||||
list_add_tail(&info->list, &pages);
|
||||
size_remaining -= (1 << info->order) * PAGE_SIZE;
|
||||
size_remaining -= PAGE_SIZE << info->order;
|
||||
max_order = info->order;
|
||||
i++;
|
||||
}
|
||||
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
if (!table)
|
||||
goto err;
|
||||
goto free_pages;
|
||||
|
||||
ret = sg_alloc_table(table, i, GFP_KERNEL);
|
||||
if (ret)
|
||||
goto err1;
|
||||
if (sg_alloc_table(table, i, GFP_KERNEL))
|
||||
goto free_table;
|
||||
|
||||
sg = table->sgl;
|
||||
list_for_each_entry_safe(info, tmp_info, &pages, list) {
|
||||
struct page *page = info->page;
|
||||
sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE, 0);
|
||||
sg_set_page(sg, page, PAGE_SIZE << info->order, 0);
|
||||
sg = sg_next(sg);
|
||||
list_del(&info->list);
|
||||
kfree(info);
|
||||
@ -185,9 +182,10 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
|
||||
|
||||
buffer->priv_virt = table;
|
||||
return 0;
|
||||
err1:
|
||||
|
||||
free_table:
|
||||
kfree(table);
|
||||
err:
|
||||
free_pages:
|
||||
list_for_each_entry_safe(info, tmp_info, &pages, list) {
|
||||
free_buffer_page(sys_heap, buffer, info->page, info->order);
|
||||
kfree(info);
|
||||
@ -197,14 +195,12 @@ err:
|
||||
|
||||
static void ion_system_heap_free(struct ion_buffer *buffer)
|
||||
{
|
||||
struct ion_heap *heap = buffer->heap;
|
||||
struct ion_system_heap *sys_heap = container_of(heap,
|
||||
struct ion_system_heap *sys_heap = container_of(buffer->heap,
|
||||
struct ion_system_heap,
|
||||
heap);
|
||||
struct sg_table *table = buffer->sg_table;
|
||||
bool cached = ion_buffer_cached(buffer);
|
||||
struct scatterlist *sg;
|
||||
LIST_HEAD(pages);
|
||||
int i;
|
||||
|
||||
/* uncached pages come from the page pools, zero them before returning
|
||||
@ -242,6 +238,7 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
|
||||
|
||||
for (i = 0; i < num_orders; i++) {
|
||||
struct ion_page_pool *pool = sys_heap->pools[i];
|
||||
|
||||
nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan);
|
||||
}
|
||||
|
||||
@ -267,14 +264,16 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
|
||||
struct ion_system_heap,
|
||||
heap);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_orders; i++) {
|
||||
struct ion_page_pool *pool = sys_heap->pools[i];
|
||||
|
||||
seq_printf(s, "%d order %u highmem pages in pool = %lu total\n",
|
||||
pool->high_count, pool->order,
|
||||
(1 << pool->order) * PAGE_SIZE * pool->high_count);
|
||||
(PAGE_SIZE << pool->order) * pool->high_count);
|
||||
seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n",
|
||||
pool->low_count, pool->order,
|
||||
(1 << pool->order) * PAGE_SIZE * pool->low_count);
|
||||
(PAGE_SIZE << pool->order) * pool->low_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -293,7 +292,7 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
|
||||
heap->pools = kzalloc(sizeof(struct ion_page_pool *) * num_orders,
|
||||
GFP_KERNEL);
|
||||
if (!heap->pools)
|
||||
goto err_alloc_pools;
|
||||
goto free_heap;
|
||||
for (i = 0; i < num_orders; i++) {
|
||||
struct ion_page_pool *pool;
|
||||
gfp_t gfp_flags = low_order_gfp_flags;
|
||||
@ -302,18 +301,18 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
|
||||
gfp_flags = high_order_gfp_flags;
|
||||
pool = ion_page_pool_create(gfp_flags, orders[i]);
|
||||
if (!pool)
|
||||
goto err_create_pool;
|
||||
goto destroy_pools;
|
||||
heap->pools[i] = pool;
|
||||
}
|
||||
|
||||
heap->heap.debug_show = ion_system_heap_debug_show;
|
||||
return &heap->heap;
|
||||
err_create_pool:
|
||||
for (i = 0; i < num_orders; i++)
|
||||
if (heap->pools[i])
|
||||
ion_page_pool_destroy(heap->pools[i]);
|
||||
|
||||
destroy_pools:
|
||||
while (i--)
|
||||
ion_page_pool_destroy(heap->pools[i]);
|
||||
kfree(heap->pools);
|
||||
err_alloc_pools:
|
||||
free_heap:
|
||||
kfree(heap);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
@ -356,15 +355,15 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap,
|
||||
for (i = len >> PAGE_SHIFT; i < (1 << order); i++)
|
||||
__free_page(page + i);
|
||||
|
||||
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
if (!table) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
goto free_pages;
|
||||
}
|
||||
|
||||
ret = sg_alloc_table(table, 1, GFP_KERNEL);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto free_table;
|
||||
|
||||
sg_set_page(table->sgl, page, len, 0);
|
||||
|
||||
@ -374,10 +373,12 @@ static int ion_system_contig_heap_allocate(struct ion_heap *heap,
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
free_table:
|
||||
kfree(table);
|
||||
free_pages:
|
||||
for (i = 0; i < len >> PAGE_SHIFT; i++)
|
||||
__free_page(page + i);
|
||||
kfree(table);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -443,4 +444,3 @@ void ion_system_contig_heap_destroy(struct ion_heap *heap)
|
||||
{
|
||||
kfree(heap);
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,7 @@ static inline struct logger_log *file_get_log(struct file *file)
|
||||
{
|
||||
if (file->f_mode & FMODE_READ) {
|
||||
struct logger_reader *reader = file->private_data;
|
||||
|
||||
return reader->log;
|
||||
} else
|
||||
return file->private_data;
|
||||
@ -124,6 +125,7 @@ static struct logger_entry *get_entry_header(struct logger_log *log,
|
||||
size_t off, struct logger_entry *scratch)
|
||||
{
|
||||
size_t len = min(sizeof(struct logger_entry), log->size - off);
|
||||
|
||||
if (len != sizeof(struct logger_entry)) {
|
||||
memcpy(((void *) scratch), log->buffer + off, len);
|
||||
memcpy(((void *) scratch) + len, log->buffer,
|
||||
@ -642,6 +644,7 @@ static unsigned int logger_poll(struct file *file, poll_table *wait)
|
||||
static long logger_set_version(struct logger_reader *reader, void __user *arg)
|
||||
{
|
||||
int version;
|
||||
|
||||
if (copy_from_user(&version, arg, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
|
||||
#define _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
|
||||
|
||||
struct ram_console_platform_data {
|
||||
const char *bootinfo;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ */
|
@ -97,6 +97,7 @@ static void sw_sync_pt_value_str(struct sync_pt *sync_pt,
|
||||
char *str, int size)
|
||||
{
|
||||
struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
|
||||
|
||||
snprintf(str, size, "%d", pt->value);
|
||||
}
|
||||
|
||||
@ -156,6 +157,7 @@ static int sw_sync_open(struct inode *inode, struct file *file)
|
||||
static int sw_sync_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct sw_sync_timeline *obj = file->private_data;
|
||||
|
||||
sync_timeline_destroy(&obj->obj);
|
||||
return 0;
|
||||
}
|
||||
|
@ -92,6 +92,10 @@ static void sync_timeline_free(struct kref *kref)
|
||||
void sync_timeline_destroy(struct sync_timeline *obj)
|
||||
{
|
||||
obj->destroyed = true;
|
||||
/*
|
||||
* Ensure timeline is marked as destroyed before
|
||||
* changing timeline's fences status.
|
||||
*/
|
||||
smp_wmb();
|
||||
|
||||
/*
|
||||
@ -384,6 +388,7 @@ static void sync_fence_detach_pts(struct sync_fence *fence)
|
||||
|
||||
list_for_each_safe(pos, n, &fence->pt_list_head) {
|
||||
struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
|
||||
|
||||
sync_timeline_remove_pt(pt);
|
||||
}
|
||||
}
|
||||
@ -394,6 +399,7 @@ static void sync_fence_free_pts(struct sync_fence *fence)
|
||||
|
||||
list_for_each_safe(pos, n, &fence->pt_list_head) {
|
||||
struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
|
||||
|
||||
sync_pt_free(pt);
|
||||
}
|
||||
}
|
||||
@ -827,6 +833,7 @@ static long sync_fence_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct sync_fence *fence = file->private_data;
|
||||
|
||||
switch (cmd) {
|
||||
case SYNC_IOC_WAIT:
|
||||
return sync_fence_ioctl_wait(fence, arg);
|
||||
@ -856,18 +863,21 @@ static const char *sync_status_str(int status)
|
||||
static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
|
||||
{
|
||||
int status = pt->status;
|
||||
|
||||
seq_printf(s, " %s%spt %s",
|
||||
fence ? pt->parent->name : "",
|
||||
fence ? "_" : "",
|
||||
sync_status_str(status));
|
||||
if (pt->status) {
|
||||
struct timeval tv = ktime_to_timeval(pt->timestamp);
|
||||
|
||||
seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec);
|
||||
}
|
||||
|
||||
if (pt->parent->ops->timeline_value_str &&
|
||||
pt->parent->ops->pt_value_str) {
|
||||
char value[64];
|
||||
|
||||
pt->parent->ops->pt_value_str(pt, value, sizeof(value));
|
||||
seq_printf(s, ": %s", value);
|
||||
if (fence) {
|
||||
@ -892,6 +902,7 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
|
||||
|
||||
if (obj->ops->timeline_value_str) {
|
||||
char value[64];
|
||||
|
||||
obj->ops->timeline_value_str(obj, value, sizeof(value));
|
||||
seq_printf(s, ": %s", value);
|
||||
} else if (obj->ops->print_obj) {
|
||||
@ -1001,6 +1012,7 @@ static void sync_dump(void)
|
||||
for (i = 0; i < s.count; i += DUMP_CHUNK) {
|
||||
if ((s.count - i) > DUMP_CHUNK) {
|
||||
char c = s.buf[i + DUMP_CHUNK];
|
||||
|
||||
s.buf[i + DUMP_CHUNK] = 0;
|
||||
pr_cont("%s", s.buf + i);
|
||||
s.buf[i + DUMP_CHUNK] = c;
|
||||
|
@ -51,6 +51,7 @@ static int gpio_get_time(struct timed_output_dev *dev)
|
||||
if (hrtimer_active(&data->timer)) {
|
||||
ktime_t r = hrtimer_get_remaining(&data->timer);
|
||||
struct timeval t = ktime_to_timeval(r);
|
||||
|
||||
return t.tv_sec * 1000 + t.tv_usec / 1000;
|
||||
} else
|
||||
return 0;
|
||||
@ -91,8 +92,8 @@ static int timed_gpio_probe(struct platform_device *pdev)
|
||||
return -EBUSY;
|
||||
|
||||
gpio_data = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct timed_gpio_data) * pdata->num_gpios,
|
||||
GFP_KERNEL);
|
||||
sizeof(struct timed_gpio_data) * pdata->num_gpios,
|
||||
GFP_KERNEL);
|
||||
if (!gpio_data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -27,12 +27,12 @@ typedef int ion_user_handle_t;
|
||||
* @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
|
||||
* @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
|
||||
* @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
|
||||
* carveout heap, allocations are physically
|
||||
* contiguous
|
||||
* carveout heap, allocations are physically
|
||||
* contiguous
|
||||
* @ION_HEAP_TYPE_DMA: memory allocated via DMA API
|
||||
* @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask
|
||||
* is used to identify the heaps, so only 32
|
||||
* total heap types are supported
|
||||
* is used to identify the heaps, so only 32
|
||||
* total heap types are supported
|
||||
*/
|
||||
enum ion_heap_type {
|
||||
ION_HEAP_TYPE_SYSTEM,
|
||||
@ -50,7 +50,7 @@ enum ion_heap_type {
|
||||
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
|
||||
#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
|
||||
|
||||
#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8
|
||||
#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
|
||||
|
||||
/**
|
||||
* allocation flags - the lower 16 bits are used by core ion, the upper 16
|
||||
@ -78,7 +78,7 @@ enum ion_heap_type {
|
||||
* @align: required alignment of the allocation
|
||||
* @heap_id_mask: mask of heap ids to allocate from
|
||||
* @flags: flags passed to heap
|
||||
* @handle: pointer that will be populated with a cookie to use to
|
||||
* @handle: pointer that will be populated with a cookie to use to
|
||||
* refer to this allocation
|
||||
*
|
||||
* Provided by userspace as an argument to the ioctl
|
||||
|
@ -1,6 +1,94 @@
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "headers.h"
|
||||
|
||||
static int bcm_handle_nvm_read_cmd(struct bcm_mini_adapter *Adapter,
|
||||
PUCHAR pReadData, struct bcm_nvm_readwrite *stNVMReadWrite)
|
||||
{
|
||||
INT Status = STATUS_FAILURE;
|
||||
|
||||
down(&Adapter->NVMRdmWrmLock);
|
||||
|
||||
if ((Adapter->IdleMode == TRUE) || (Adapter->bShutStatus == TRUE) ||
|
||||
(Adapter->bPreparingForLowPowerMode == TRUE)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter,
|
||||
DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Device is in Idle/Shutdown Mode\n");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
kfree(pReadData);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
Status = BeceemNVMRead(Adapter, (PUINT)pReadData,
|
||||
stNVMReadWrite->uiOffset,
|
||||
stNVMReadWrite->uiNumBytes);
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
|
||||
if (Status != STATUS_SUCCESS) {
|
||||
kfree(pReadData);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (copy_to_user(stNVMReadWrite->pBuffer, pReadData,
|
||||
stNVMReadWrite->uiNumBytes)) {
|
||||
kfree(pReadData);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int handle_flash2x_adapter(struct bcm_mini_adapter *Adapter,
|
||||
PUCHAR pReadData, struct bcm_nvm_readwrite *stNVMReadWrite)
|
||||
{
|
||||
/*
|
||||
* New Requirement:-
|
||||
* DSD section updation will be allowed in two case:-
|
||||
* 1. if DSD sig is present in DSD header means dongle
|
||||
* is ok and updation is fruitfull
|
||||
* 2. if point 1 failes then user buff should have
|
||||
* DSD sig. this point ensures that if dongle is
|
||||
* corrupted then user space program first modify
|
||||
* the DSD header with valid DSD sig so that this
|
||||
* as well as further write may be worthwhile.
|
||||
*
|
||||
* This restriction has been put assuming that
|
||||
* if DSD sig is corrupted, DSD data won't be
|
||||
* considered valid.
|
||||
*/
|
||||
INT Status;
|
||||
ULONG ulDSDMagicNumInUsrBuff = 0;
|
||||
|
||||
Status = BcmFlash2xCorruptSig(Adapter, Adapter->eActiveDSD);
|
||||
if (Status == STATUS_SUCCESS)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
if (((stNVMReadWrite->uiOffset + stNVMReadWrite->uiNumBytes) !=
|
||||
Adapter->uiNVMDSDSize) ||
|
||||
(stNVMReadWrite->uiNumBytes < SIGNATURE_SIZE)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"DSD Sig is present neither in Flash nor User provided Input..");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
kfree(pReadData);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ulDSDMagicNumInUsrBuff =
|
||||
ntohl(*(PUINT)(pReadData + stNVMReadWrite->uiNumBytes -
|
||||
SIGNATURE_SIZE));
|
||||
if (ulDSDMagicNumInUsrBuff != DSD_IMAGE_MAGIC_NUMBER) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"DSD Sig is present neither in Flash nor User provided Input..");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
kfree(pReadData);
|
||||
return Status;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Function - bcm_char_open()
|
||||
*
|
||||
@ -101,9 +189,11 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size,
|
||||
int wait_ret_val = 0;
|
||||
unsigned long ret = 0;
|
||||
|
||||
wait_ret_val = wait_event_interruptible(Adapter->process_read_wait_queue,
|
||||
(pTarang->RxAppControlHead ||
|
||||
Adapter->device_removed));
|
||||
wait_ret_val = wait_event_interruptible(
|
||||
Adapter->process_read_wait_queue,
|
||||
(pTarang->RxAppControlHead ||
|
||||
Adapter->device_removed));
|
||||
|
||||
if ((wait_ret_val == -ERESTARTSYS)) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Exiting as i've been asked to exit!!!\n");
|
||||
@ -151,7 +241,7 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_reg_read_private(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_rdm_buffer sRdmBuffer = {0};
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
@ -202,7 +292,7 @@ static int bcm_char_ioctl_reg_read_private(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_reg_write_private(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_wrm_buffer sWrmBuffer = {0};
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
@ -249,7 +339,7 @@ static int bcm_char_ioctl_reg_write_private(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_eeprom_reg_read(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_rdm_buffer sRdmBuffer = {0};
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
@ -317,7 +407,8 @@ static int bcm_char_ioctl_eeprom_reg_read(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_eeprom_reg_write(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter, UINT cmd)
|
||||
struct bcm_mini_adapter *Adapter,
|
||||
UINT cmd)
|
||||
{
|
||||
struct bcm_wrm_buffer sWrmBuffer = {0};
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
@ -383,7 +474,7 @@ static int bcm_char_ioctl_eeprom_reg_write(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_gpio_set_request(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_gpio_info gpio_info = {0};
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
@ -410,7 +501,8 @@ static int bcm_char_ioctl_gpio_set_request(void __user *argp,
|
||||
if (IoBuffer.InputLength > sizeof(gpio_info))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
|
||||
if (copy_from_user(&gpio_info, IoBuffer.InputBuffer,
|
||||
IoBuffer.InputLength))
|
||||
return -EFAULT;
|
||||
|
||||
uiBit = gpio_info.uiGpioNumber;
|
||||
@ -492,7 +584,7 @@ static int bcm_char_ioctl_gpio_set_request(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_led_thread_state_change_req(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_user_thread_req threadReq = {0};
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
@ -516,7 +608,8 @@ static int bcm_char_ioctl_led_thread_state_change_req(void __user *argp,
|
||||
if (IoBuffer.InputLength > sizeof(threadReq))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength))
|
||||
if (copy_from_user(&threadReq, IoBuffer.InputBuffer,
|
||||
IoBuffer.InputLength))
|
||||
return -EFAULT;
|
||||
|
||||
/* if LED thread is running(Actively or Inactively)
|
||||
@ -542,7 +635,7 @@ static int bcm_char_ioctl_led_thread_state_change_req(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_gpio_status_request(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_gpio_info gpio_info = {0};
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
@ -584,7 +677,7 @@ static int bcm_char_ioctl_gpio_status_request(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_gpio_multi_info gpio_multi_info[MAX_IDX];
|
||||
struct bcm_gpio_multi_info *pgpio_multi_info =
|
||||
@ -594,7 +687,8 @@ static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
|
||||
INT Status = STATUS_FAILURE;
|
||||
int bytes;
|
||||
|
||||
memset(pgpio_multi_info, 0, MAX_IDX * sizeof(struct bcm_gpio_multi_info));
|
||||
memset(pgpio_multi_info, 0,
|
||||
MAX_IDX * sizeof(struct bcm_gpio_multi_info));
|
||||
|
||||
if ((Adapter->IdleMode == TRUE) ||
|
||||
(Adapter->bShutStatus == TRUE) ||
|
||||
@ -610,11 +704,11 @@ static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
|
||||
IoBuffer.OutputLength = sizeof(gpio_multi_info);
|
||||
|
||||
if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer,
|
||||
IoBuffer.InputLength))
|
||||
IoBuffer.InputLength))
|
||||
return -EFAULT;
|
||||
|
||||
if (IsReqGpioIsLedInNVM(Adapter,
|
||||
pgpio_multi_info[WIMAX_IDX].uiGPIOMask) == false) {
|
||||
if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_info[WIMAX_IDX].uiGPIOMask)
|
||||
== false) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
|
||||
DBG_LVL_ALL,
|
||||
"Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",
|
||||
@ -627,7 +721,7 @@ static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
|
||||
if ((pgpio_multi_info[WIMAX_IDX].uiGPIOMask) &
|
||||
(pgpio_multi_info[WIMAX_IDX].uiGPIOCommand)) {
|
||||
/* Set 1's in GPIO OUTPUT REGISTER */
|
||||
*(UINT *)ucResetValue = pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
|
||||
*(UINT *)ucResetValue = pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
|
||||
pgpio_multi_info[WIMAX_IDX].uiGPIOCommand &
|
||||
pgpio_multi_info[WIMAX_IDX].uiGPIOValue;
|
||||
|
||||
@ -643,7 +737,8 @@ static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
|
||||
}
|
||||
|
||||
/* Clear to 0's in GPIO OUTPUT REGISTER */
|
||||
*(UINT *)ucResetValue = (pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
|
||||
*(UINT *)ucResetValue =
|
||||
(pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
|
||||
pgpio_multi_info[WIMAX_IDX].uiGPIOCommand &
|
||||
(~(pgpio_multi_info[WIMAX_IDX].uiGPIOValue)));
|
||||
|
||||
@ -661,7 +756,7 @@ static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
|
||||
|
||||
if (pgpio_multi_info[WIMAX_IDX].uiGPIOMask) {
|
||||
bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER,
|
||||
(PUINT)ucResetValue, sizeof(UINT));
|
||||
(PUINT)ucResetValue, sizeof(UINT));
|
||||
|
||||
if (bytes < 0) {
|
||||
Status = bytes;
|
||||
@ -672,7 +767,8 @@ static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
pgpio_multi_info[WIMAX_IDX].uiGPIOValue = (*(UINT *)ucResetValue &
|
||||
pgpio_multi_info[WIMAX_IDX].uiGPIOValue =
|
||||
(*(UINT *)ucResetValue &
|
||||
pgpio_multi_info[WIMAX_IDX].uiGPIOMask);
|
||||
}
|
||||
|
||||
@ -688,7 +784,7 @@ static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_gpio_mode_request(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_gpio_multi_mode gpio_multi_mode[MAX_IDX];
|
||||
struct bcm_gpio_multi_mode *pgpio_multi_mode =
|
||||
@ -728,8 +824,8 @@ static int bcm_char_ioctl_gpio_mode_request(void __user *argp,
|
||||
}
|
||||
|
||||
/* Validating the request */
|
||||
if (IsReqGpioIsLedInNVM(Adapter,
|
||||
pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) == false) {
|
||||
if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_mode[WIMAX_IDX].uiGPIOMask)
|
||||
== false) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",
|
||||
pgpio_multi_mode[WIMAX_IDX].uiGPIOMask,
|
||||
@ -739,11 +835,13 @@ static int bcm_char_ioctl_gpio_mode_request(void __user *argp,
|
||||
|
||||
if (pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) {
|
||||
/* write all OUT's (1's) */
|
||||
*(UINT *) ucResetValue |= (pgpio_multi_mode[WIMAX_IDX].uiGPIOMode &
|
||||
*(UINT *) ucResetValue |=
|
||||
(pgpio_multi_mode[WIMAX_IDX].uiGPIOMode &
|
||||
pgpio_multi_mode[WIMAX_IDX].uiGPIOMask);
|
||||
|
||||
/* write all IN's (0's) */
|
||||
*(UINT *) ucResetValue &= ~((~pgpio_multi_mode[WIMAX_IDX].uiGPIOMode) &
|
||||
*(UINT *) ucResetValue &=
|
||||
~((~pgpio_multi_mode[WIMAX_IDX].uiGPIOMode) &
|
||||
pgpio_multi_mode[WIMAX_IDX].uiGPIOMask);
|
||||
|
||||
/* Currently implemented return the modes of all GPIO's
|
||||
@ -779,7 +877,7 @@ static int bcm_char_ioctl_gpio_mode_request(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_misc_request(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
PVOID pvBuffer = NULL;
|
||||
@ -801,9 +899,11 @@ static int bcm_char_ioctl_misc_request(void __user *argp,
|
||||
return PTR_ERR(pvBuffer);
|
||||
|
||||
down(&Adapter->LowPowerModeSync);
|
||||
Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue,
|
||||
!Adapter->bPreparingForLowPowerMode,
|
||||
(1 * HZ));
|
||||
Status = wait_event_interruptible_timeout(
|
||||
Adapter->lowpower_mode_wait_queue,
|
||||
!Adapter->bPreparingForLowPowerMode,
|
||||
(1 * HZ));
|
||||
|
||||
if (Status == -ERESTARTSYS)
|
||||
goto cntrlEnd;
|
||||
|
||||
@ -822,7 +922,7 @@ cntrlEnd:
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_buffer_download_start(
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
INT Status;
|
||||
|
||||
@ -833,7 +933,8 @@ static int bcm_char_ioctl_buffer_download_start(
|
||||
}
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Starting the firmware download PID =0x%x!!!!\n", current->pid);
|
||||
"Starting the firmware download PID =0x%x!!!!\n",
|
||||
current->pid);
|
||||
|
||||
if (down_trylock(&Adapter->fw_download_sema))
|
||||
return -EBUSY;
|
||||
@ -858,7 +959,7 @@ static int bcm_char_ioctl_buffer_download_start(
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_buffer_download(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_firmware_info *psFwInfo = NULL;
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
@ -943,7 +1044,7 @@ static int bcm_char_ioctl_buffer_download(void __user *argp,
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_buffer_download_stop(void __user *argp,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
INT Status;
|
||||
int timeout = 0;
|
||||
@ -1036,7 +1137,7 @@ static int bcm_char_ioctl_chip_reset(struct bcm_mini_adapter *Adapter)
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_qos_threshold(ULONG arg,
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
USHORT uiLoopIndex;
|
||||
|
||||
@ -1388,7 +1489,6 @@ static int bcm_char_ioctl_nvm_rw(void __user *argp,
|
||||
struct timeval tv0, tv1;
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
PUCHAR pReadData = NULL;
|
||||
ULONG ulDSDMagicNumInUsrBuff = 0;
|
||||
INT Status = STATUS_FAILURE;
|
||||
|
||||
memset(&tv0, 0, sizeof(struct timeval));
|
||||
@ -1438,34 +1538,10 @@ static int bcm_char_ioctl_nvm_rw(void __user *argp,
|
||||
|
||||
do_gettimeofday(&tv0);
|
||||
if (IOCTL_BCM_NVM_READ == cmd) {
|
||||
down(&Adapter->NVMRdmWrmLock);
|
||||
|
||||
if ((Adapter->IdleMode == TRUE) ||
|
||||
(Adapter->bShutStatus == TRUE) ||
|
||||
(Adapter->bPreparingForLowPowerMode == TRUE)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter,
|
||||
DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Device is in Idle/Shutdown Mode\n");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
kfree(pReadData);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
Status = BeceemNVMRead(Adapter, (PUINT)pReadData,
|
||||
stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes);
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
|
||||
if (Status != STATUS_SUCCESS) {
|
||||
kfree(pReadData);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (copy_to_user(stNVMReadWrite.pBuffer, pReadData,
|
||||
stNVMReadWrite.uiNumBytes)) {
|
||||
kfree(pReadData);
|
||||
return -EFAULT;
|
||||
}
|
||||
int ret = bcm_handle_nvm_read_cmd(Adapter, pReadData,
|
||||
&stNVMReadWrite);
|
||||
if (ret != STATUS_SUCCESS)
|
||||
return ret;
|
||||
} else {
|
||||
down(&Adapter->NVMRdmWrmLock);
|
||||
|
||||
@ -1483,48 +1559,11 @@ static int bcm_char_ioctl_nvm_rw(void __user *argp,
|
||||
|
||||
Adapter->bHeaderChangeAllowed = TRUE;
|
||||
if (IsFlash2x(Adapter)) {
|
||||
/*
|
||||
* New Requirement:-
|
||||
* DSD section updation will be allowed in two case:-
|
||||
* 1. if DSD sig is present in DSD header means dongle
|
||||
* is ok and updation is fruitfull
|
||||
* 2. if point 1 failes then user buff should have
|
||||
* DSD sig. this point ensures that if dongle is
|
||||
* corrupted then user space program first modify
|
||||
* the DSD header with valid DSD sig so that this
|
||||
* as well as further write may be worthwhile.
|
||||
*
|
||||
* This restriction has been put assuming that
|
||||
* if DSD sig is corrupted, DSD data won't be
|
||||
* considered valid.
|
||||
*/
|
||||
|
||||
Status = BcmFlash2xCorruptSig(Adapter,
|
||||
Adapter->eActiveDSD);
|
||||
if (Status != STATUS_SUCCESS) {
|
||||
if (((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) !=
|
||||
Adapter->uiNVMDSDSize) ||
|
||||
(stNVMReadWrite.uiNumBytes < SIGNATURE_SIZE)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
|
||||
OSAL_DBG, DBG_LVL_ALL,
|
||||
"DSD Sig is present neither in Flash nor User provided Input..");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
kfree(pReadData);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ulDSDMagicNumInUsrBuff = ntohl(*(PUINT)(pReadData + stNVMReadWrite.uiNumBytes - SIGNATURE_SIZE));
|
||||
if (ulDSDMagicNumInUsrBuff !=
|
||||
DSD_IMAGE_MAGIC_NUMBER) {
|
||||
BCM_DEBUG_PRINT(Adapter,
|
||||
DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"DSD Sig is present neither in Flash nor User provided Input..");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
kfree(pReadData);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
int ret = handle_flash2x_adapter(Adapter,
|
||||
pReadData,
|
||||
&stNVMReadWrite);
|
||||
if (ret != STATUS_SUCCESS)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Status = BeceemNVMWrite(Adapter, (PUINT)pReadData,
|
||||
@ -1546,7 +1585,8 @@ static int bcm_char_ioctl_nvm_rw(void __user *argp,
|
||||
do_gettimeofday(&tv1);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
" timetaken by Write/read :%ld msec\n",
|
||||
(tv1.tv_sec - tv0.tv_sec)*1000 + (tv1.tv_usec - tv0.tv_usec)/1000);
|
||||
(tv1.tv_sec - tv0.tv_sec)*1000 +
|
||||
(tv1.tv_usec - tv0.tv_usec)/1000);
|
||||
|
||||
kfree(pReadData);
|
||||
return STATUS_SUCCESS;
|
||||
@ -1582,13 +1622,17 @@ static int bcm_char_ioctl_flash2x_section_read(void __user *argp,
|
||||
return -EFAULT;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"\nsFlash2xRead.Section :%x", sFlash2xRead.Section);
|
||||
"\nsFlash2xRead.Section :%x",
|
||||
sFlash2xRead.Section);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"\nsFlash2xRead.offset :%x", sFlash2xRead.offset);
|
||||
"\nsFlash2xRead.offset :%x",
|
||||
sFlash2xRead.offset);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"\nsFlash2xRead.numOfBytes :%x", sFlash2xRead.numOfBytes);
|
||||
"\nsFlash2xRead.numOfBytes :%x",
|
||||
sFlash2xRead.numOfBytes);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"\nsFlash2xRead.bVerify :%x\n", sFlash2xRead.bVerify);
|
||||
"\nsFlash2xRead.bVerify :%x\n",
|
||||
sFlash2xRead.bVerify);
|
||||
|
||||
/* This was internal to driver for raw read.
|
||||
* now it has ben exposed to user space app.
|
||||
@ -1608,7 +1652,7 @@ static int bcm_char_ioctl_flash2x_section_read(void __user *argp,
|
||||
|
||||
if (pReadBuff == NULL) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Memory allocation failed for Flash 2.x Read Structure");
|
||||
"Memory allocation failed for Flash 2.x Read Structure");
|
||||
return -ENOMEM;
|
||||
}
|
||||
down(&Adapter->NVMRdmWrmLock);
|
||||
@ -1618,7 +1662,8 @@ static int bcm_char_ioctl_flash2x_section_read(void __user *argp,
|
||||
(Adapter->bPreparingForLowPowerMode == TRUE)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
|
||||
DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
|
||||
DBG_LVL_ALL,
|
||||
"Device is in Idle/Shutdown Mode\n");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
kfree(pReadBuff);
|
||||
return -EACCES;
|
||||
@ -1735,8 +1780,10 @@ static int bcm_char_ioctl_flash2x_section_write(void __user *argp,
|
||||
|
||||
/* extracting the remainder of the given offset. */
|
||||
WriteBytes = Adapter->uiSectorSize;
|
||||
if (WriteOffset % Adapter->uiSectorSize)
|
||||
WriteBytes = Adapter->uiSectorSize - (WriteOffset % Adapter->uiSectorSize);
|
||||
if (WriteOffset % Adapter->uiSectorSize) {
|
||||
WriteBytes = Adapter->uiSectorSize -
|
||||
(WriteOffset % Adapter->uiSectorSize);
|
||||
}
|
||||
|
||||
if (NOB < WriteBytes)
|
||||
WriteBytes = NOB;
|
||||
@ -1769,8 +1816,10 @@ static int bcm_char_ioctl_flash2x_section_write(void __user *argp,
|
||||
|
||||
/* Writing the data from Flash 2.x */
|
||||
Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pWriteBuff,
|
||||
sFlash2xWrite.Section, WriteOffset, WriteBytes,
|
||||
sFlash2xWrite.bVerify);
|
||||
sFlash2xWrite.Section,
|
||||
WriteOffset,
|
||||
WriteBytes,
|
||||
sFlash2xWrite.bVerify);
|
||||
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
@ -1800,7 +1849,6 @@ static int bcm_char_ioctl_flash2x_section_bitmap(void __user *argp,
|
||||
{
|
||||
struct bcm_flash2x_bitmap *psFlash2xBitMap;
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
INT Status = STATUS_FAILURE;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called");
|
||||
@ -1811,7 +1859,9 @@ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
if (IoBuffer.OutputLength != sizeof(struct bcm_flash2x_bitmap))
|
||||
return -EINVAL;
|
||||
|
||||
psFlash2xBitMap = kzalloc(sizeof(struct bcm_flash2x_bitmap), GFP_KERNEL);
|
||||
psFlash2xBitMap = kzalloc(sizeof(struct bcm_flash2x_bitmap),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (psFlash2xBitMap == NULL) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Memory is not available");
|
||||
@ -1841,7 +1891,7 @@ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
}
|
||||
|
||||
kfree(psFlash2xBitMap);
|
||||
return Status;
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
|
||||
static int bcm_char_ioctl_set_active_section(void __user *argp,
|
||||
@ -1852,23 +1902,24 @@ static int bcm_char_ioctl_set_active_section(void __user *argp,
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"IOCTL_BCM_SET_ACTIVE_SECTION Called");
|
||||
"IOCTL_BCM_SET_ACTIVE_SECTION Called");
|
||||
|
||||
if (IsFlash2x(Adapter) != TRUE) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Flash Does not have 2.x map");
|
||||
"Flash Does not have 2.x map");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
|
||||
Status = copy_from_user(&IoBuffer, argp,
|
||||
sizeof(struct bcm_ioctl_buffer));
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Copy of IOCTL BUFFER failed");
|
||||
"Copy of IOCTL BUFFER failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
Status = copy_from_user(&eFlash2xSectionVal,
|
||||
IoBuffer.InputBuffer, sizeof(INT));
|
||||
IoBuffer.InputBuffer, sizeof(INT));
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Copy of flash section val failed");
|
||||
@ -1882,7 +1933,7 @@ static int bcm_char_ioctl_set_active_section(void __user *argp,
|
||||
(Adapter->bPreparingForLowPowerMode == TRUE)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Device is in Idle/Shutdown Mode\n");
|
||||
"Device is in Idle/Shutdown Mode\n");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
return -EACCES;
|
||||
}
|
||||
@ -1890,8 +1941,8 @@ static int bcm_char_ioctl_set_active_section(void __user *argp,
|
||||
Status = BcmSetActiveSection(Adapter, eFlash2xSectionVal);
|
||||
if (Status)
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Failed to make it's priority Highest. Status %d",
|
||||
Status);
|
||||
"Failed to make it's priority Highest. Status %d",
|
||||
Status);
|
||||
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
|
||||
@ -1906,57 +1957,59 @@ static int bcm_char_ioctl_copy_section(void __user *argp,
|
||||
INT Status = STATUS_SUCCESS;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"IOCTL_BCM_COPY_SECTION Called");
|
||||
"IOCTL_BCM_COPY_SECTION Called");
|
||||
|
||||
Adapter->bAllDSDWriteAllow = false;
|
||||
if (IsFlash2x(Adapter) != TRUE) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Flash Does not have 2.x map");
|
||||
"Flash Does not have 2.x map");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
|
||||
Status = copy_from_user(&IoBuffer, argp,
|
||||
sizeof(struct bcm_ioctl_buffer));
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Copy of IOCTL BUFFER failed Status :%d", Status);
|
||||
"Copy of IOCTL BUFFER failed Status :%d",
|
||||
Status);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer,
|
||||
sizeof(struct bcm_flash2x_copy_section));
|
||||
sizeof(struct bcm_flash2x_copy_section));
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Copy of Copy_Section_Struct failed with Status :%d",
|
||||
Status);
|
||||
"Copy of Copy_Section_Struct failed with Status :%d",
|
||||
Status);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Source SEction :%x", sCopySectStrut.SrcSection);
|
||||
"Source SEction :%x", sCopySectStrut.SrcSection);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Destination SEction :%x", sCopySectStrut.DstSection);
|
||||
"Destination SEction :%x", sCopySectStrut.DstSection);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"offset :%x", sCopySectStrut.offset);
|
||||
"offset :%x", sCopySectStrut.offset);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"NOB :%x", sCopySectStrut.numOfBytes);
|
||||
"NOB :%x", sCopySectStrut.numOfBytes);
|
||||
|
||||
if (IsSectionExistInFlash(Adapter, sCopySectStrut.SrcSection) == false) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Source Section<%x> does not exist in Flash ",
|
||||
sCopySectStrut.SrcSection);
|
||||
"Source Section<%x> does not exist in Flash ",
|
||||
sCopySectStrut.SrcSection);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (IsSectionExistInFlash(Adapter, sCopySectStrut.DstSection) == false) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Destinatio Section<%x> does not exist in Flash ",
|
||||
sCopySectStrut.DstSection);
|
||||
"Destinatio Section<%x> does not exist in Flash ",
|
||||
sCopySectStrut.DstSection);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sCopySectStrut.SrcSection == sCopySectStrut.DstSection) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Source and Destination section should be different");
|
||||
"Source and Destination section should be different");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1967,7 +2020,7 @@ static int bcm_char_ioctl_copy_section(void __user *argp,
|
||||
(Adapter->bPreparingForLowPowerMode == TRUE)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Device is in Idle/Shutdown Mode\n");
|
||||
"Device is in Idle/Shutdown Mode\n");
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
return -EACCES;
|
||||
}
|
||||
@ -1976,13 +2029,13 @@ static int bcm_char_ioctl_copy_section(void __user *argp,
|
||||
sCopySectStrut.SrcSection == ISO_IMAGE2) {
|
||||
if (IsNonCDLessDevice(Adapter)) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Device is Non-CDLess hence won't have ISO !!");
|
||||
"Device is Non-CDLess hence won't have ISO !!");
|
||||
Status = -EINVAL;
|
||||
} else if (sCopySectStrut.numOfBytes == 0) {
|
||||
Status = BcmCopyISO(Adapter, sCopySectStrut);
|
||||
} else {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Partial Copy of ISO section is not Allowed..");
|
||||
"Partial Copy of ISO section is not Allowed..");
|
||||
Status = STATUS_FAILURE;
|
||||
}
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
@ -2004,18 +2057,19 @@ static int bcm_char_ioctl_get_flash_cs_info(void __user *argp,
|
||||
INT Status = STATUS_SUCCESS;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
" IOCTL_BCM_GET_FLASH_CS_INFO Called");
|
||||
" IOCTL_BCM_GET_FLASH_CS_INFO Called");
|
||||
|
||||
Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
|
||||
Status = copy_from_user(&IoBuffer, argp,
|
||||
sizeof(struct bcm_ioctl_buffer));
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Copy of IOCTL BUFFER failed");
|
||||
"Copy of IOCTL BUFFER failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (Adapter->eNVMType != NVM_FLASH) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Connected device does not have flash");
|
||||
"Connected device does not have flash");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -2024,15 +2078,15 @@ static int bcm_char_ioctl_get_flash_cs_info(void __user *argp,
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_to_user(IoBuffer.OutputBuffer,
|
||||
Adapter->psFlash2xCSInfo,
|
||||
sizeof(struct bcm_flash2x_cs_info)))
|
||||
Adapter->psFlash2xCSInfo,
|
||||
sizeof(struct bcm_flash2x_cs_info)))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
if (IoBuffer.OutputLength < sizeof(struct bcm_flash_cs_info))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo,
|
||||
sizeof(struct bcm_flash_cs_info)))
|
||||
sizeof(struct bcm_flash_cs_info)))
|
||||
return -EFAULT;
|
||||
}
|
||||
return Status;
|
||||
@ -2048,45 +2102,46 @@ static int bcm_char_ioctl_select_dsd(void __user *argp,
|
||||
|
||||
eFlash2xSectionVal = NO_SECTION_VAL;
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"IOCTL_BCM_SELECT_DSD Called");
|
||||
"IOCTL_BCM_SELECT_DSD Called");
|
||||
|
||||
if (IsFlash2x(Adapter) != TRUE) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Flash Does not have 2.x map");
|
||||
"Flash Does not have 2.x map");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
|
||||
Status = copy_from_user(&IoBuffer, argp,
|
||||
sizeof(struct bcm_ioctl_buffer));
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Copy of IOCTL BUFFER failed");
|
||||
"Copy of IOCTL BUFFER failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer,
|
||||
sizeof(INT));
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Copy of flash section val failed");
|
||||
"Copy of flash section val failed");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Read Section :%d", eFlash2xSectionVal);
|
||||
"Read Section :%d", eFlash2xSectionVal);
|
||||
if ((eFlash2xSectionVal != DSD0) &&
|
||||
(eFlash2xSectionVal != DSD1) &&
|
||||
(eFlash2xSectionVal != DSD2)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Passed section<%x> is not DSD section",
|
||||
eFlash2xSectionVal);
|
||||
"Passed section<%x> is not DSD section",
|
||||
eFlash2xSectionVal);
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
|
||||
SectOfset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal);
|
||||
if (SectOfset == INVALID_OFFSET) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Provided Section val <%d> does not exist in Flash 2.x",
|
||||
eFlash2xSectionVal);
|
||||
"Provided Section val <%d> does not exist in Flash 2.x",
|
||||
eFlash2xSectionVal);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -2112,14 +2167,14 @@ static int bcm_char_ioctl_nvm_raw_read(void __user *argp,
|
||||
|
||||
if (Adapter->eNVMType != NVM_FLASH) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"NVM TYPE is not Flash");
|
||||
"NVM TYPE is not Flash");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Copy Ioctl Buffer structure */
|
||||
if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"copy_from_user 1 failed\n");
|
||||
"copy_from_user 1 failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
@ -2141,7 +2196,7 @@ static int bcm_char_ioctl_nvm_raw_read(void __user *argp,
|
||||
pReadBuff = kzalloc(BuffSize , GFP_KERNEL);
|
||||
if (pReadBuff == NULL) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Memory allocation failed for Flash 2.x Read Structure");
|
||||
"Memory allocation failed for Flash 2.x Read Structure");
|
||||
return -ENOMEM;
|
||||
}
|
||||
down(&Adapter->NVMRdmWrmLock);
|
||||
@ -2150,8 +2205,8 @@ static int bcm_char_ioctl_nvm_raw_read(void __user *argp,
|
||||
(Adapter->bShutStatus == TRUE) ||
|
||||
(Adapter->bPreparingForLowPowerMode == TRUE)) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
|
||||
DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Device is in Idle/Shutdown Mode\n");
|
||||
kfree(pReadBuff);
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
return -EACCES;
|
||||
@ -2170,17 +2225,19 @@ static int bcm_char_ioctl_nvm_raw_read(void __user *argp,
|
||||
ReadOffset, ReadBytes);
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Flash 2x read err with Status :%d", Status);
|
||||
"Flash 2x read err with Status :%d",
|
||||
Status);
|
||||
break;
|
||||
}
|
||||
|
||||
BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
|
||||
DBG_LVL_ALL, pReadBuff, ReadBytes);
|
||||
DBG_LVL_ALL, pReadBuff, ReadBytes);
|
||||
|
||||
Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes);
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Copy to use failed with status :%d", Status);
|
||||
"Copy to use failed with status :%d",
|
||||
Status);
|
||||
up(&Adapter->NVMRdmWrmLock);
|
||||
kfree(pReadBuff);
|
||||
return -EFAULT;
|
||||
@ -2205,26 +2262,27 @@ static int bcm_char_ioctl_cntrlmsg_mask(void __user *argp,
|
||||
ULONG RxCntrlMsgBitMask = 0;
|
||||
|
||||
/* Copy Ioctl Buffer structure */
|
||||
Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
|
||||
Status = copy_from_user(&IoBuffer, argp,
|
||||
sizeof(struct bcm_ioctl_buffer));
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"copy of Ioctl buffer is failed from user space");
|
||||
"copy of Ioctl buffer is failed from user space");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (IoBuffer.InputLength != sizeof(unsigned long))
|
||||
return -EINVAL;
|
||||
|
||||
Status = copy_from_user(&RxCntrlMsgBitMask,
|
||||
IoBuffer.InputBuffer, IoBuffer.InputLength);
|
||||
Status = copy_from_user(&RxCntrlMsgBitMask, IoBuffer.InputBuffer,
|
||||
IoBuffer.InputLength);
|
||||
if (Status) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"copy of control bit mask failed from user space");
|
||||
"copy of control bit mask failed from user space");
|
||||
return -EFAULT;
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"\n Got user defined cntrl msg bit mask :%lx",
|
||||
RxCntrlMsgBitMask);
|
||||
"\n Got user defined cntrl msg bit mask :%lx",
|
||||
RxCntrlMsgBitMask);
|
||||
pTarang->RxCntrlMsgBitMask = RxCntrlMsgBitMask;
|
||||
|
||||
return Status;
|
||||
@ -2236,8 +2294,8 @@ static int bcm_char_ioctl_get_device_driver_info(void __user *argp,
|
||||
struct bcm_driver_info DevInfo;
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
|
||||
DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n");
|
||||
|
||||
memset(&DevInfo, 0, sizeof(DevInfo));
|
||||
DevInfo.MaxRDMBufferSize = BUFFER_4K;
|
||||
@ -2265,7 +2323,7 @@ static int bcm_char_ioctl_time_since_net_entry(void __user *argp,
|
||||
struct bcm_ioctl_buffer IoBuffer;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"IOCTL_BCM_TIME_SINCE_NET_ENTRY called");
|
||||
"IOCTL_BCM_TIME_SINCE_NET_ENTRY called");
|
||||
|
||||
if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
|
||||
return -EFAULT;
|
||||
@ -2277,7 +2335,7 @@ static int bcm_char_ioctl_time_since_net_entry(void __user *argp,
|
||||
get_seconds() - Adapter->liTimeSinceLastNetEntry;
|
||||
|
||||
if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry,
|
||||
sizeof(struct bcm_time_elapsed)))
|
||||
sizeof(struct bcm_time_elapsed)))
|
||||
return -EFAULT;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
@ -2355,7 +2413,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
|
||||
return Status;
|
||||
|
||||
case BCM_LED_THREAD_STATE_CHANGE_REQ:
|
||||
Status = bcm_char_ioctl_led_thread_state_change_req(argp, Adapter);
|
||||
Status = bcm_char_ioctl_led_thread_state_change_req(argp,
|
||||
Adapter);
|
||||
return Status;
|
||||
|
||||
case IOCTL_BCM_GPIO_STATUS_REQUEST:
|
||||
@ -2394,13 +2453,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
|
||||
|
||||
case IOCTL_BE_BUCKET_SIZE:
|
||||
Status = 0;
|
||||
if (get_user(Adapter->BEBucketSize, (unsigned long __user *)arg))
|
||||
if (get_user(Adapter->BEBucketSize,
|
||||
(unsigned long __user *)arg))
|
||||
Status = -EFAULT;
|
||||
break;
|
||||
|
||||
case IOCTL_RTPS_BUCKET_SIZE:
|
||||
Status = 0;
|
||||
if (get_user(Adapter->rtPSBucketSize, (unsigned long __user *)arg))
|
||||
if (get_user(Adapter->rtPSBucketSize,
|
||||
(unsigned long __user *)arg))
|
||||
Status = -EFAULT;
|
||||
break;
|
||||
|
||||
@ -2420,7 +2481,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
|
||||
|
||||
case IOCTL_GET_PACK_INFO:
|
||||
if (copy_to_user(argp, &Adapter->PackInfo,
|
||||
sizeof(struct bcm_packet_info)*NO_OF_QUEUES))
|
||||
sizeof(struct bcm_packet_info)*NO_OF_QUEUES))
|
||||
return -EFAULT;
|
||||
Status = STATUS_SUCCESS;
|
||||
break;
|
||||
@ -2451,7 +2512,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
|
||||
|
||||
case IOCTL_BCM_WAKE_UP_DEVICE_FROM_IDLE:
|
||||
if ((false == Adapter->bTriedToWakeUpFromlowPowerMode) &&
|
||||
(TRUE == Adapter->IdleMode)) {
|
||||
(TRUE == Adapter->IdleMode)) {
|
||||
Adapter->usIdleModePattern = ABORT_IDLE_MODE;
|
||||
Adapter->bWakeUpDevice = TRUE;
|
||||
wake_up(&Adapter->process_rx_cntrlpkt);
|
||||
@ -2501,7 +2562,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
|
||||
/* Right Now we are taking care of only DSD */
|
||||
Adapter->bAllDSDWriteAllow = false;
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called");
|
||||
"IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called");
|
||||
Status = STATUS_SUCCESS;
|
||||
break;
|
||||
|
||||
@ -2534,8 +2595,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
|
||||
return Status;
|
||||
|
||||
case IOCTL_CLOSE_NOTIFICATION:
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
|
||||
DBG_LVL_ALL, "IOCTL_CLOSE_NOTIFICATION");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
|
||||
"IOCTL_CLOSE_NOTIFICATION");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2569,8 +2630,8 @@ int register_control_device_interface(struct bcm_mini_adapter *Adapter)
|
||||
}
|
||||
|
||||
Adapter->pstCreatedClassDevice = device_create(bcm_class, NULL,
|
||||
MKDEV(Adapter->major, 0),
|
||||
Adapter, DEV_NAME);
|
||||
MKDEV(Adapter->major, 0),
|
||||
Adapter, DEV_NAME);
|
||||
|
||||
if (IS_ERR(Adapter->pstCreatedClassDevice)) {
|
||||
pr_err(DRV_NAME ": class device create failed\n");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -53,8 +53,8 @@ int InterfaceFileReadbackFromChip(PVOID arg, struct file *flp,
|
||||
struct bcm_interface_adapter *psIntfAdapter = arg;
|
||||
int bytes;
|
||||
|
||||
buff = kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA);
|
||||
buff_readback = kmalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA);
|
||||
buff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA);
|
||||
buff_readback = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA);
|
||||
if (!buff || !buff_readback) {
|
||||
kfree(buff);
|
||||
kfree(buff_readback);
|
||||
@ -64,8 +64,6 @@ int InterfaceFileReadbackFromChip(PVOID arg, struct file *flp,
|
||||
|
||||
is_config_file = (on_chip_loc == CONFIG_BEGIN_ADDR) ? 1 : 0;
|
||||
|
||||
memset(buff_readback, 0, MAX_TRANSFER_CTRL_BYTE_USB);
|
||||
memset(buff, 0, MAX_TRANSFER_CTRL_BYTE_USB);
|
||||
while (1) {
|
||||
oldfs = get_fs();
|
||||
set_fs(get_ds());
|
||||
|
@ -223,7 +223,6 @@ static int InterfaceAbortIdlemode(struct bcm_mini_adapter *Adapter,
|
||||
}
|
||||
int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
ULONG Status = 0;
|
||||
if (Adapter->bTriedToWakeUpFromlowPowerMode) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
|
||||
IDLE_MODE, DBG_LVL_ALL,
|
||||
@ -233,7 +232,7 @@ int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter)
|
||||
InterfaceAbortIdlemode(Adapter, Adapter->usIdleModePattern);
|
||||
|
||||
}
|
||||
return Status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter)
|
||||
|
@ -14,13 +14,13 @@ InterfaceWRM(struct bcm_interface_adapter *psIntfAdapter,
|
||||
INT len);
|
||||
|
||||
|
||||
int InterfaceFileDownload( PVOID psIntfAdapter,
|
||||
struct file *flp,
|
||||
unsigned int on_chip_loc);
|
||||
int InterfaceFileDownload(PVOID psIntfAdapter,
|
||||
struct file *flp,
|
||||
unsigned int on_chip_loc);
|
||||
|
||||
int InterfaceFileReadbackFromChip( PVOID psIntfAdapter,
|
||||
struct file *flp,
|
||||
unsigned int on_chip_loc);
|
||||
int InterfaceFileReadbackFromChip(PVOID psIntfAdapter,
|
||||
struct file *flp,
|
||||
unsigned int on_chip_loc);
|
||||
|
||||
|
||||
int BcmRDM(PVOID arg,
|
||||
|
@ -409,7 +409,6 @@ ULONG PhsUpdateClassifierRule(IN void *pvContext,
|
||||
*/
|
||||
ULONG PhsDeletePHSRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT8 u8PHSI)
|
||||
{
|
||||
ULONG lStatus = 0;
|
||||
UINT nSFIndex = 0, nClsidIndex = 0;
|
||||
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
|
||||
struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL;
|
||||
@ -446,7 +445,7 @@ ULONG PhsDeletePHSRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT8 u8PHSI
|
||||
}
|
||||
}
|
||||
}
|
||||
return lStatus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -467,7 +466,6 @@ ULONG PhsDeletePHSRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT8 u8PHSI
|
||||
*/
|
||||
ULONG PhsDeleteClassifierRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT16 uiClsId)
|
||||
{
|
||||
ULONG lStatus = 0;
|
||||
UINT nSFIndex = 0, nClsidIndex = 0;
|
||||
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
|
||||
struct bcm_phs_classifier_entry *pstClassifierEntry = NULL;
|
||||
@ -504,7 +502,7 @@ ULONG PhsDeleteClassifierRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT1
|
||||
memset(pstClassifierEntry, 0, sizeof(struct bcm_phs_classifier_entry));
|
||||
}
|
||||
}
|
||||
return lStatus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -524,7 +522,6 @@ ULONG PhsDeleteClassifierRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT1
|
||||
*/
|
||||
ULONG PhsDeleteSFRules(IN void *pvContext, IN B_UINT16 uiVcid)
|
||||
{
|
||||
ULONG lStatus = 0;
|
||||
UINT nSFIndex = 0, nClsidIndex = 0;
|
||||
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
|
||||
struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL;
|
||||
@ -573,7 +570,7 @@ ULONG PhsDeleteSFRules(IN void *pvContext, IN B_UINT16 uiVcid)
|
||||
pstServiceFlowEntry->uiVcid = 0;
|
||||
}
|
||||
|
||||
return lStatus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4,11 +4,18 @@ This file contains the routines related to Quality of Service.
|
||||
*/
|
||||
#include "headers.h"
|
||||
|
||||
static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, PVOID pvEthPayload, struct bcm_eth_packet_info *pstEthCsPktInfo);
|
||||
static bool EThCSClassifyPkt(struct bcm_mini_adapter *Adapter, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo, struct bcm_classifier_rule *pstClassifierRule, B_UINT8 EthCSCupport);
|
||||
static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter,
|
||||
PVOID pvEthPayload,
|
||||
struct bcm_eth_packet_info *pstEthCsPktInfo);
|
||||
|
||||
static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, struct iphdr *iphd,
|
||||
struct bcm_classifier_rule *pstClassifierRule);
|
||||
static bool EThCSClassifyPkt(struct bcm_mini_adapter *Adapter,
|
||||
struct sk_buff *skb,
|
||||
struct bcm_eth_packet_info *pstEthCsPktInfo,
|
||||
struct bcm_classifier_rule *pstClassifierRule,
|
||||
B_UINT8 EthCSCupport);
|
||||
|
||||
static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, struct iphdr *iphd,
|
||||
struct bcm_classifier_rule *pstClassifierRule);
|
||||
|
||||
static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex);
|
||||
|
||||
@ -33,14 +40,11 @@ static bool MatchSrcIpAddress(struct bcm_classifier_rule *pstClassifierRule, ULO
|
||||
ulSrcIP = ntohl(ulSrcIP);
|
||||
if (0 == pstClassifierRule->ucIPSourceAddressLength)
|
||||
return TRUE;
|
||||
for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength); ucLoopIndex++)
|
||||
{
|
||||
for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength); ucLoopIndex++) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Mask:0x%x PacketIp:0x%x and Classification:0x%x", (UINT)pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)ulSrcIP, (UINT)pstClassifierRule->stSrcIpAddress.ulIpv6Addr[ucLoopIndex]);
|
||||
if ((pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] & ulSrcIP) ==
|
||||
(pstClassifierRule->stSrcIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex]))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Not Matched");
|
||||
return false;
|
||||
@ -68,13 +72,10 @@ static bool MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule, UL
|
||||
return TRUE;
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address 0x%x 0x%x 0x%x ", (UINT)ulDestIP, (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex]);
|
||||
|
||||
for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPDestinationAddressLength); ucLoopIndex++)
|
||||
{
|
||||
for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPDestinationAddressLength); ucLoopIndex++) {
|
||||
if ((pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex] & ulDestIP) ==
|
||||
(pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex]))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address Not Matched");
|
||||
return false;
|
||||
@ -99,9 +100,8 @@ static bool MatchTos(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucType
|
||||
return TRUE;
|
||||
|
||||
if (((pstClassifierRule->ucTosMask & ucTypeOfService) <= pstClassifierRule->ucTosHigh) && ((pstClassifierRule->ucTosMask & ucTypeOfService) >= pstClassifierRule->ucTosLow))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Type Of Service Not Matched");
|
||||
return false;
|
||||
}
|
||||
@ -123,13 +123,10 @@ bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucProtoc
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
if (0 == pstClassifierRule->ucProtocolLength)
|
||||
return TRUE;
|
||||
for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucProtocolLength; ucLoopIndex++)
|
||||
{
|
||||
for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucProtocolLength; ucLoopIndex++) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol:0x%X Classification Protocol:0x%X", ucProtocol, pstClassifierRule->ucProtocol[ucLoopIndex]);
|
||||
if (pstClassifierRule->ucProtocol[ucLoopIndex] == ucProtocol)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Not Matched");
|
||||
return false;
|
||||
@ -155,13 +152,10 @@ bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushSrcPo
|
||||
|
||||
if (0 == pstClassifierRule->ucSrcPortRangeLength)
|
||||
return TRUE;
|
||||
for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucSrcPortRangeLength; ucLoopIndex++)
|
||||
{
|
||||
for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucSrcPortRangeLength; ucLoopIndex++) {
|
||||
if (ushSrcPort <= pstClassifierRule->usSrcPortRangeHi[ucLoopIndex] &&
|
||||
ushSrcPort >= pstClassifierRule->usSrcPortRangeLo[ucLoopIndex])
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port: %x Not Matched ", ushSrcPort);
|
||||
return false;
|
||||
@ -186,15 +180,12 @@ bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushDest
|
||||
if (0 == pstClassifierRule->ucDestPortRangeLength)
|
||||
return TRUE;
|
||||
|
||||
for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucDestPortRangeLength; ucLoopIndex++)
|
||||
{
|
||||
for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucDestPortRangeLength; ucLoopIndex++) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Matching Port:0x%X 0x%X 0x%X", ushDestPort, pstClassifierRule->usDestPortRangeLo[ucLoopIndex], pstClassifierRule->usDestPortRangeHi[ucLoopIndex]);
|
||||
|
||||
if (ushDestPort <= pstClassifierRule->usDestPortRangeHi[ucLoopIndex] &&
|
||||
ushDestPort >= pstClassifierRule->usDestPortRangeLo[ucLoopIndex])
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dest Port: %x Not Matched", ushDestPort);
|
||||
return false;
|
||||
@ -273,21 +264,13 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter,
|
||||
bClassificationSucceed = TRUE;
|
||||
} while (0);
|
||||
|
||||
if (TRUE == bClassificationSucceed)
|
||||
{
|
||||
if (TRUE == bClassificationSucceed) {
|
||||
INT iMatchedSFQueueIndex = 0;
|
||||
iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
|
||||
if (iMatchedSFQueueIndex >= NO_OF_QUEUES)
|
||||
{
|
||||
bClassificationSucceed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (false == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
|
||||
{
|
||||
bClassificationSucceed = false;
|
||||
}
|
||||
}
|
||||
else if (false == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
|
||||
bClassificationSucceed = false;
|
||||
}
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "IpVersion4 <==========");
|
||||
@ -299,8 +282,7 @@ VOID PruneQueueAllSF(struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
UINT iIndex = 0;
|
||||
|
||||
for (iIndex = 0; iIndex < HiPriority; iIndex++)
|
||||
{
|
||||
for (iIndex = 0; iIndex < HiPriority; iIndex++) {
|
||||
if (!Adapter->PackInfo[iIndex].bValid)
|
||||
continue;
|
||||
|
||||
@ -334,10 +316,10 @@ static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex)
|
||||
|
||||
spin_lock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
|
||||
|
||||
while (1)
|
||||
while (1) {
|
||||
// while((UINT)Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost >
|
||||
// SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
|
||||
{
|
||||
// SF_MAX_ALLOWED_PACKETS_TO_BACKUP) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "uiCurrentBytesOnHost:%x uiMaxBucketSize :%x",
|
||||
Adapter->PackInfo[iIndex].uiCurrentBytesOnHost,
|
||||
Adapter->PackInfo[iIndex].uiMaxBucketSize);
|
||||
@ -350,8 +332,7 @@ static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex)
|
||||
((1000*(jiffies - *((B_UINT32 *)(PacketToDrop->cb)+SKB_CB_LATENCY_OFFSET))/HZ) <= Adapter->PackInfo[iIndex].uiMaxLatency))
|
||||
break;
|
||||
|
||||
if (PacketToDrop)
|
||||
{
|
||||
if (PacketToDrop) {
|
||||
if (netif_msg_tx_err(Adapter))
|
||||
pr_info(PFX "%s: tx queue %d overlimit\n",
|
||||
Adapter->dev->name, iIndex);
|
||||
@ -394,20 +375,16 @@ VOID flush_all_queues(struct bcm_mini_adapter *Adapter)
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>");
|
||||
|
||||
// down(&Adapter->data_packet_queue_lock);
|
||||
for (iQIndex = LowPriority; iQIndex < HiPriority; iQIndex++)
|
||||
{
|
||||
for (iQIndex = LowPriority; iQIndex < HiPriority; iQIndex++) {
|
||||
struct net_device_stats *netstats = &Adapter->dev->stats;
|
||||
|
||||
spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
|
||||
while (Adapter->PackInfo[iQIndex].FirstTxQueue)
|
||||
{
|
||||
while (Adapter->PackInfo[iQIndex].FirstTxQueue) {
|
||||
PacketToDrop = Adapter->PackInfo[iQIndex].FirstTxQueue;
|
||||
if (PacketToDrop)
|
||||
{
|
||||
if (PacketToDrop) {
|
||||
uiTotalPacketLength = PacketToDrop->len;
|
||||
netstats->tx_dropped++;
|
||||
}
|
||||
else
|
||||
} else
|
||||
uiTotalPacketLength = 0;
|
||||
|
||||
DEQUEUEPACKET(Adapter->PackInfo[iQIndex].FirstTxQueue,
|
||||
@ -455,58 +432,42 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb)
|
||||
*((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET) = 0;
|
||||
EThCSGetPktInfo(Adapter, pvEThPayload, &stEthCsPktInfo);
|
||||
|
||||
switch (stEthCsPktInfo.eNwpktEthFrameType)
|
||||
{
|
||||
switch (stEthCsPktInfo.eNwpktEthFrameType) {
|
||||
case eEth802LLCFrame:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802LLCFrame\n");
|
||||
pIpHeader = pvEThPayload + sizeof(struct bcm_eth_llc_frame);
|
||||
break;
|
||||
}
|
||||
|
||||
case eEth802LLCSNAPFrame:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802LLC SNAP Frame\n");
|
||||
pIpHeader = pvEThPayload + sizeof(struct bcm_eth_llc_snap_frame);
|
||||
break;
|
||||
}
|
||||
case eEth802QVLANFrame:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802.1Q VLANFrame\n");
|
||||
pIpHeader = pvEThPayload + sizeof(struct bcm_eth_q_frame);
|
||||
break;
|
||||
}
|
||||
case eEthOtherFrame:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : ETH Other Frame\n");
|
||||
pIpHeader = pvEThPayload + sizeof(struct bcm_ethernet2_frame);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : Unrecognized ETH Frame\n");
|
||||
pIpHeader = pvEThPayload + sizeof(struct bcm_ethernet2_frame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
|
||||
{
|
||||
if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet) {
|
||||
usCurrFragment = (ntohs(pIpHeader->frag_off) & IP_OFFSET);
|
||||
if ((ntohs(pIpHeader->frag_off) & IP_MF) || usCurrFragment)
|
||||
bFragmentedPkt = TRUE;
|
||||
|
||||
if (bFragmentedPkt)
|
||||
{
|
||||
if (bFragmentedPkt) {
|
||||
//Fragmented Packet. Get Frag Classifier Entry.
|
||||
pstClassifierRule = GetFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr);
|
||||
if (pstClassifierRule)
|
||||
{
|
||||
if (pstClassifierRule) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "It is next Fragmented pkt");
|
||||
bClassificationSucceed = TRUE;
|
||||
}
|
||||
if (!(ntohs(pIpHeader->frag_off) & IP_MF))
|
||||
{
|
||||
if (!(ntohs(pIpHeader->frag_off) & IP_MF)) {
|
||||
//Fragmented Last packet . Remove Frag Classifier Entry
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "This is the last fragmented Pkt");
|
||||
DelFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr);
|
||||
@ -514,23 +475,19 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb)
|
||||
}
|
||||
}
|
||||
|
||||
for (uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--)
|
||||
{
|
||||
for (uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--) {
|
||||
if (bClassificationSucceed)
|
||||
break;
|
||||
//Iterate through all classifiers which are already in order of priority
|
||||
//to classify the packet until match found
|
||||
do
|
||||
{
|
||||
if (false == Adapter->astClassifierTable[uiLoopIndex].bUsed)
|
||||
{
|
||||
do {
|
||||
if (false == Adapter->astClassifierTable[uiLoopIndex].bUsed) {
|
||||
bClassificationSucceed = false;
|
||||
break;
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Adapter->PackInfo[%d].bvalid=True\n", uiLoopIndex);
|
||||
|
||||
if (0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection)
|
||||
{
|
||||
if (0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection) {
|
||||
bClassificationSucceed = false;//cannot be processed for classification.
|
||||
break; // it is a down link connection
|
||||
}
|
||||
@ -543,11 +500,9 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb)
|
||||
break;
|
||||
}
|
||||
|
||||
if (Adapter->PackInfo[uiSfIndex].bEthCSSupport)
|
||||
{
|
||||
if (Adapter->PackInfo[uiSfIndex].bEthCSSupport) {
|
||||
|
||||
if (eEthUnsupportedFrame == stEthCsPktInfo.eNwpktEthFrameType)
|
||||
{
|
||||
if (eEthUnsupportedFrame == stEthCsPktInfo.eNwpktEthFrameType) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a Valid Supported Ethernet Frame\n");
|
||||
bClassificationSucceed = false;
|
||||
break;
|
||||
@ -558,17 +513,12 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb)
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Performing ETH CS Classification on Classifier Rule ID : %x Service Flow ID : %lx\n", pstClassifierRule->uiClassifierRuleIndex, Adapter->PackInfo[uiSfIndex].ulSFID);
|
||||
bClassificationSucceed = EThCSClassifyPkt(Adapter, skb, &stEthCsPktInfo, pstClassifierRule, Adapter->PackInfo[uiSfIndex].bEthCSSupport);
|
||||
|
||||
if (!bClassificationSucceed)
|
||||
{
|
||||
if (!bClassificationSucceed) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : Ethernet CS Classification Failed\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else // No ETH Supported on this SF
|
||||
{
|
||||
if (eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType)
|
||||
{
|
||||
} else { // No ETH Supported on this SF
|
||||
if (eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a 802.3 Ethernet Frame... hence not allowed over non-ETH CS SF\n");
|
||||
bClassificationSucceed = false;
|
||||
break;
|
||||
@ -577,11 +527,9 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb)
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Proceeding to IP CS Clasification");
|
||||
|
||||
if (Adapter->PackInfo[uiSfIndex].bIPCSSupport)
|
||||
{
|
||||
if (Adapter->PackInfo[uiSfIndex].bIPCSSupport) {
|
||||
|
||||
if (stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket)
|
||||
{
|
||||
if (stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet is Not an IP Packet\n");
|
||||
bClassificationSucceed = false;
|
||||
break;
|
||||
@ -598,31 +546,26 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb)
|
||||
} while (0);
|
||||
}
|
||||
|
||||
if (bClassificationSucceed == TRUE)
|
||||
{
|
||||
if (bClassificationSucceed == TRUE) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "CF id : %d, SF ID is =%lu", pstClassifierRule->uiClassifierRuleIndex, pstClassifierRule->ulSFID);
|
||||
|
||||
//Store The matched Classifier in SKB
|
||||
*((UINT32*)(skb->cb)+SKB_CB_CLASSIFICATION_OFFSET) = pstClassifierRule->uiClassifierRuleIndex;
|
||||
if ((TCP == pIpHeader->protocol) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len))
|
||||
{
|
||||
if ((TCP == pIpHeader->protocol) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len)) {
|
||||
IpHeaderLength = pIpHeader->ihl;
|
||||
pTcpHeader = (struct bcm_tcp_header *)(((PUCHAR)pIpHeader)+(IpHeaderLength*4));
|
||||
TcpHeaderLength = GET_TCP_HEADER_LEN(pTcpHeader->HeaderLength);
|
||||
|
||||
if ((pTcpHeader->ucFlags & TCP_ACK) &&
|
||||
(ntohs(pIpHeader->tot_len) == (IpHeaderLength*4)+(TcpHeaderLength*4)))
|
||||
{
|
||||
*((UINT32*) (skb->cb) + SKB_CB_TCPACK_OFFSET) = TCP_ACK;
|
||||
}
|
||||
}
|
||||
|
||||
usIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "index is =%d", usIndex);
|
||||
|
||||
//If this is the first fragment of a Fragmented pkt, add this CF. Only This CF should be used for all other fragment of this Pkt.
|
||||
if (bFragmentedPkt && (usCurrFragment == 0))
|
||||
{
|
||||
if (bFragmentedPkt && (usCurrFragment == 0)) {
|
||||
//First Fragment of Fragmented Packet. Create Frag CLS Entry
|
||||
struct bcm_fragmented_packet_info stFragPktInfo;
|
||||
stFragPktInfo.bUsed = TRUE;
|
||||
@ -648,9 +591,8 @@ static bool EthCSMatchSrcMACAddress(struct bcm_classifier_rule *pstClassifierRul
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
if (pstClassifierRule->ucEthCSSrcMACLen == 0)
|
||||
return TRUE;
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __FUNCTION__);
|
||||
for (i = 0; i < MAC_ADDRESS_SIZE; i++)
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __func__);
|
||||
for (i = 0; i < MAC_ADDRESS_SIZE; i++) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSSrcMAC[i], pstClassifierRule->au8EThCSSrcMACMask[i]);
|
||||
if ((pstClassifierRule->au8EThCSSrcMAC[i] & pstClassifierRule->au8EThCSSrcMACMask[i]) !=
|
||||
(Mac[i] & pstClassifierRule->au8EThCSSrcMACMask[i]))
|
||||
@ -665,9 +607,8 @@ static bool EthCSMatchDestMACAddress(struct bcm_classifier_rule *pstClassifierRu
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
if (pstClassifierRule->ucEthCSDestMACLen == 0)
|
||||
return TRUE;
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __FUNCTION__);
|
||||
for (i = 0; i < MAC_ADDRESS_SIZE; i++)
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __func__);
|
||||
for (i = 0; i < MAC_ADDRESS_SIZE; i++) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSDestMAC[i], pstClassifierRule->au8EThCSDestMACMask[i]);
|
||||
if ((pstClassifierRule->au8EThCSDestMAC[i] & pstClassifierRule->au8EThCSDestMACMask[i]) !=
|
||||
(Mac[i] & pstClassifierRule->au8EThCSDestMACMask[i]))
|
||||
@ -683,10 +624,9 @@ static bool EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule,
|
||||
(pstClassifierRule->au8EthCSEtherType[0] == 0))
|
||||
return TRUE;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s SrcEtherType:%x CLS EtherType[0]:%x\n", __FUNCTION__, pstEthCsPktInfo->usEtherType, pstClassifierRule->au8EthCSEtherType[0]);
|
||||
if (pstClassifierRule->au8EthCSEtherType[0] == 1)
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS EtherType[1]:%x EtherType[2]:%x\n", __FUNCTION__, pstClassifierRule->au8EthCSEtherType[1], pstClassifierRule->au8EthCSEtherType[2]);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s SrcEtherType:%x CLS EtherType[0]:%x\n", __func__, pstEthCsPktInfo->usEtherType, pstClassifierRule->au8EthCSEtherType[0]);
|
||||
if (pstClassifierRule->au8EthCSEtherType[0] == 1) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS EtherType[1]:%x EtherType[2]:%x\n", __func__, pstClassifierRule->au8EthCSEtherType[1], pstClassifierRule->au8EthCSEtherType[2]);
|
||||
|
||||
if (memcmp(&pstEthCsPktInfo->usEtherType, &pstClassifierRule->au8EthCSEtherType[1], 2) == 0)
|
||||
return TRUE;
|
||||
@ -694,12 +634,11 @@ static bool EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pstClassifierRule->au8EthCSEtherType[0] == 2)
|
||||
{
|
||||
if (pstClassifierRule->au8EthCSEtherType[0] == 2) {
|
||||
if (eEth802LLCFrame != pstEthCsPktInfo->eNwpktEthFrameType)
|
||||
return false;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s EthCS DSAP:%x EtherType[2]:%x\n", __FUNCTION__, pstEthCsPktInfo->ucDSAP, pstClassifierRule->au8EthCSEtherType[2]);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s EthCS DSAP:%x EtherType[2]:%x\n", __func__, pstEthCsPktInfo->ucDSAP, pstClassifierRule->au8EthCSEtherType[2]);
|
||||
if (pstEthCsPktInfo->ucDSAP == pstClassifierRule->au8EthCSEtherType[2])
|
||||
return TRUE;
|
||||
else
|
||||
@ -718,11 +657,10 @@ static bool EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule, s
|
||||
B_UINT8 uPriority = 0;
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS UserPrio:%x CLS VLANID:%x\n", __FUNCTION__, ntohs(*((USHORT *)pstClassifierRule->usUserPriority)), pstClassifierRule->usVLANID);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS UserPrio:%x CLS VLANID:%x\n", __func__, ntohs(*((USHORT *)pstClassifierRule->usUserPriority)), pstClassifierRule->usVLANID);
|
||||
|
||||
/* In case FW didn't receive the TLV, the priority field should be ignored */
|
||||
if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_USER_PRIORITY_VALID))
|
||||
{
|
||||
if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_USER_PRIORITY_VALID)) {
|
||||
if (pstEthCsPktInfo->eNwpktEthFrameType != eEth802QVLANFrame)
|
||||
return false;
|
||||
|
||||
@ -739,14 +677,13 @@ static bool EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule, s
|
||||
|
||||
bClassificationSucceed = false;
|
||||
|
||||
if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_VLANID_VALID))
|
||||
{
|
||||
if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_VLANID_VALID)) {
|
||||
if (pstEthCsPktInfo->eNwpktEthFrameType != eEth802QVLANFrame)
|
||||
return false;
|
||||
|
||||
usVLANID = ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xFFF;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s Pkt VLANID %x Priority: %d\n", __FUNCTION__, usVLANID, uPriority);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s Pkt VLANID %x Priority: %d\n", __func__, usVLANID, uPriority);
|
||||
|
||||
if (usVLANID == ((pstClassifierRule->usVLANID & 0xFFF0) >> 4))
|
||||
bClassificationSucceed = TRUE;
|
||||
@ -800,32 +737,24 @@ static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, PVOID pvEthPayload
|
||||
USHORT u16Etype = ntohs(((struct bcm_eth_header *)pvEthPayload)->u16Etype);
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : Eth Hdr Type : %X\n", u16Etype);
|
||||
if (u16Etype > 0x5dc)
|
||||
{
|
||||
if (u16Etype > 0x5dc) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : ETH2 Frame\n");
|
||||
//ETH2 Frame
|
||||
if (u16Etype == ETHERNET_FRAMETYPE_802QVLAN)
|
||||
{
|
||||
if (u16Etype == ETHERNET_FRAMETYPE_802QVLAN) {
|
||||
//802.1Q VLAN Header
|
||||
pstEthCsPktInfo->eNwpktEthFrameType = eEth802QVLANFrame;
|
||||
u16Etype = ((struct bcm_eth_q_frame *)pvEthPayload)->EthType;
|
||||
//((ETH_CS_802_Q_FRAME*)pvEthPayload)->UserPriority
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
pstEthCsPktInfo->eNwpktEthFrameType = eEthOtherFrame;
|
||||
u16Etype = ntohs(u16Etype);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
//802.2 LLC
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "802.2 LLC Frame\n");
|
||||
pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCFrame;
|
||||
pstEthCsPktInfo->ucDSAP = ((struct bcm_eth_llc_frame *)pvEthPayload)->DSAP;
|
||||
if (pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA)
|
||||
{
|
||||
if (pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA) {
|
||||
//SNAP Frame
|
||||
pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCSNAPFrame;
|
||||
u16Etype = ((struct bcm_eth_llc_snap_frame *)pvEthPayload)->usEtherType;
|
||||
|
@ -46,12 +46,14 @@ int SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket)
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
|
||||
if (!pControlPacket || !Adapter) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got NULL Control Packet or Adapter");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL,
|
||||
"Got NULL Control Packet or Adapter");
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
if ((atomic_read(&Adapter->CurrNumFreeTxDesc) <
|
||||
((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1)) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL,
|
||||
"NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
|
||||
@ -109,7 +111,8 @@ int SetupNextSend(struct bcm_mini_adapter *Adapter, struct sk_buff *Packet, USH
|
||||
(UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
|
||||
|
||||
if (status != STATUS_SUCCESS) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,
|
||||
"PHS Transmit failed..\n");
|
||||
goto errExit;
|
||||
}
|
||||
|
||||
@ -217,12 +220,15 @@ int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter obje
|
||||
Adapter->LinkStatus == SYNC_UP_REQUEST &&
|
||||
!Adapter->bSyncUpRequestSent) {
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS,
|
||||
DBG_LVL_ALL, "Calling LinkMessage");
|
||||
LinkMessage(Adapter);
|
||||
}
|
||||
|
||||
if ((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount)) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device in Low Power mode...waking up");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX,
|
||||
TX_PACKETS, DBG_LVL_ALL,
|
||||
"Device in Low Power mode...waking up");
|
||||
Adapter->usIdleModePattern = ABORT_IDLE_MODE;
|
||||
Adapter->bWakeUpDevice = TRUE;
|
||||
wake_up(&Adapter->process_rx_cntrlpkt);
|
||||
@ -232,7 +238,8 @@ int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter obje
|
||||
atomic_set(&Adapter->TxPktAvail, 0);
|
||||
}
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL,
|
||||
"Exiting the tx thread..\n");
|
||||
Adapter->transmit_packet_thread = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,37 +9,40 @@
|
||||
|
||||
#include "headers.h"
|
||||
|
||||
INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_mibs *pstHostMibs)
|
||||
INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter,
|
||||
struct bcm_host_stats_mibs *pstHostMibs)
|
||||
{
|
||||
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
|
||||
struct bcm_phs_rule *pstPhsRule = NULL;
|
||||
struct bcm_phs_classifier_table *pstClassifierTable = NULL;
|
||||
struct bcm_phs_classifier_entry *pstClassifierRule = NULL;
|
||||
struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *) &Adapter->stBCMPhsContext;
|
||||
|
||||
UINT nClassifierIndex = 0, nPhsTableIndex = 0, nSfIndex = 0, uiIndex = 0;
|
||||
struct bcm_phs_extension *pDeviceExtension = &Adapter->stBCMPhsContext;
|
||||
UINT nClassifierIndex = 0;
|
||||
UINT nPhsTableIndex = 0;
|
||||
UINT nSfIndex = 0;
|
||||
UINT uiIndex = 0;
|
||||
|
||||
if (pDeviceExtension == NULL) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, HOST_MIBS, DBG_LVL_ALL, "Invalid Device Extension\n");
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, HOST_MIBS,
|
||||
DBG_LVL_ALL, "Invalid Device Extension\n");
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
|
||||
/* Copy the classifier Table */
|
||||
for (nClassifierIndex = 0; nClassifierIndex < MAX_CLASSIFIERS; nClassifierIndex++) {
|
||||
for (nClassifierIndex = 0; nClassifierIndex < MAX_CLASSIFIERS;
|
||||
nClassifierIndex++) {
|
||||
if (Adapter->astClassifierTable[nClassifierIndex].bUsed == TRUE)
|
||||
memcpy((PVOID) &pstHostMibs->
|
||||
astClassifierTable[nClassifierIndex],
|
||||
(PVOID) &Adapter->
|
||||
astClassifierTable[nClassifierIndex],
|
||||
memcpy(&pstHostMibs->astClassifierTable[nClassifierIndex],
|
||||
&Adapter->astClassifierTable[nClassifierIndex],
|
||||
sizeof(struct bcm_mibs_classifier_rule));
|
||||
}
|
||||
|
||||
/* Copy the SF Table */
|
||||
for (nSfIndex = 0; nSfIndex < NO_OF_QUEUES; nSfIndex++) {
|
||||
if (Adapter->PackInfo[nSfIndex].bValid) {
|
||||
memcpy((PVOID) &pstHostMibs->astSFtable[nSfIndex],
|
||||
(PVOID) &Adapter->PackInfo[nSfIndex],
|
||||
sizeof(struct bcm_mibs_table));
|
||||
memcpy(&pstHostMibs->astSFtable[nSfIndex],
|
||||
&Adapter->PackInfo[nSfIndex],
|
||||
sizeof(struct bcm_mibs_table));
|
||||
} else {
|
||||
/* If index in not valid,
|
||||
* don't process this for the PHS table.
|
||||
@ -68,9 +71,9 @@ INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_m
|
||||
pstHostMibs->astPhsRulesTable[nPhsTableIndex].
|
||||
ulSFID = Adapter->PackInfo[nSfIndex].ulSFID;
|
||||
|
||||
memcpy(&pstHostMibs->
|
||||
astPhsRulesTable[nPhsTableIndex].u8PHSI,
|
||||
&pstPhsRule->u8PHSI, sizeof(struct bcm_phs_rule));
|
||||
memcpy(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI,
|
||||
&pstPhsRule->u8PHSI,
|
||||
sizeof(struct bcm_phs_rule));
|
||||
nPhsTableIndex++;
|
||||
|
||||
}
|
||||
@ -82,26 +85,32 @@ INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_m
|
||||
/* Copy other Host Statistics parameters */
|
||||
pstHostMibs->stHostInfo.GoodTransmits = Adapter->dev->stats.tx_packets;
|
||||
pstHostMibs->stHostInfo.GoodReceives = Adapter->dev->stats.rx_packets;
|
||||
pstHostMibs->stHostInfo.CurrNumFreeDesc = atomic_read(&Adapter->CurrNumFreeTxDesc);
|
||||
pstHostMibs->stHostInfo.CurrNumFreeDesc =
|
||||
atomic_read(&Adapter->CurrNumFreeTxDesc);
|
||||
pstHostMibs->stHostInfo.BEBucketSize = Adapter->BEBucketSize;
|
||||
pstHostMibs->stHostInfo.rtPSBucketSize = Adapter->rtPSBucketSize;
|
||||
pstHostMibs->stHostInfo.TimerActive = Adapter->TimerActive;
|
||||
pstHostMibs->stHostInfo.u32TotalDSD = Adapter->u32TotalDSD;
|
||||
|
||||
memcpy(pstHostMibs->stHostInfo.aTxPktSizeHist, Adapter->aTxPktSizeHist, sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES);
|
||||
memcpy(pstHostMibs->stHostInfo.aRxPktSizeHist, Adapter->aRxPktSizeHist, sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES);
|
||||
memcpy(pstHostMibs->stHostInfo.aTxPktSizeHist, Adapter->aTxPktSizeHist,
|
||||
sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES);
|
||||
memcpy(pstHostMibs->stHostInfo.aRxPktSizeHist, Adapter->aRxPktSizeHist,
|
||||
sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID GetDroppedAppCntrlPktMibs(struct bcm_host_stats_mibs *pstHostMibs, struct bcm_tarang_data *pTarang)
|
||||
VOID GetDroppedAppCntrlPktMibs(struct bcm_host_stats_mibs *pstHostMibs,
|
||||
struct bcm_tarang_data *pTarang)
|
||||
{
|
||||
memcpy(&(pstHostMibs->stDroppedAppCntrlMsgs),
|
||||
&(pTarang->stDroppedAppCntrlMsgs),
|
||||
sizeof(struct bcm_mibs_dropped_cntrl_msg));
|
||||
}
|
||||
|
||||
VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, struct bcm_connect_mgr_params *psfLocalSet, UINT uiSearchRuleIndex)
|
||||
VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter,
|
||||
struct bcm_connect_mgr_params *psfLocalSet,
|
||||
UINT uiSearchRuleIndex)
|
||||
{
|
||||
struct bcm_mibs_parameters *t = &Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable;
|
||||
|
||||
|
@ -160,16 +160,18 @@ config COMEDI_PCL730
|
||||
Enable support for various simple ISA or PC/104 Digital I/O boards.
|
||||
These boards all use 8-bit I/O ports.
|
||||
|
||||
Advantech PCL-730 isolated - 16 in/16 out ttl - 16 in/16 out
|
||||
ICP ISO-730 isolated - 16 in/16 out ttl - 16 in/16 out
|
||||
ADlink ACL-7130 isolated - 16 in/16 out ttl - 16 in/16 out
|
||||
Advantech PCM-3730 isolated - 8 in/8 out ttl - 16 in/16 out
|
||||
Advantech PCL-725 isolated - 8 in/8 out
|
||||
ICP P8R8-DIO isolated - 8 in/8 out
|
||||
ADlink ACL-7225b isolated - 16 in/16 out
|
||||
ICP P16R16-DIO isolated - 16 in/16 out
|
||||
Advantech PCL-733 isolated - 32 in
|
||||
Advantech PCL-734 isolated - 32 out
|
||||
Advantech PCL-730 iso - 16 in/16 out ttl - 16 in/16 out
|
||||
ICP ISO-730 iso - 16 in/16 out ttl - 16 in/16 out
|
||||
ADlink ACL-7130 iso - 16 in/16 out ttl - 16 in/16 out
|
||||
Advantech PCM-3730 iso - 8 in/8 out ttl - 16 in/16 out
|
||||
Advantech PCL-725 iso - 8 in/8 out
|
||||
ICP P8R8-DIO iso - 8 in/8 out
|
||||
ADlink ACL-7225b iso - 16 in/16 out
|
||||
ICP P16R16-DIO iso - 16 in/16 out
|
||||
Advantech PCL-733 iso - 32 in
|
||||
Advantech PCL-734 iso - 32 out
|
||||
Diamond Systems OPMM-1616-XT iso - 16 in/16 out
|
||||
Diamond Systems PEARL-MM-P iso - 16 out
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called pcl730.
|
||||
|
@ -3,7 +3,6 @@ TODO:
|
||||
- Lindent
|
||||
- remove all wrappers
|
||||
- audit userspace interface
|
||||
- reserve major number
|
||||
- cleanup the individual comedi drivers as well
|
||||
|
||||
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
|
||||
|
@ -183,9 +183,9 @@ comedi_buf_map_from_subdev_get(struct comedi_subdevice *s)
|
||||
return bm;
|
||||
}
|
||||
|
||||
bool comedi_buf_is_mmapped(struct comedi_async *async)
|
||||
bool comedi_buf_is_mmapped(struct comedi_subdevice *s)
|
||||
{
|
||||
struct comedi_buf_map *bm = async->buf_map;
|
||||
struct comedi_buf_map *bm = s->async->buf_map;
|
||||
|
||||
return bm && (atomic_read(&bm->refcount.refcount) > 1);
|
||||
}
|
||||
@ -222,8 +222,10 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void comedi_buf_reset(struct comedi_async *async)
|
||||
void comedi_buf_reset(struct comedi_subdevice *s)
|
||||
{
|
||||
struct comedi_async *async = s->async;
|
||||
|
||||
async->buf_write_alloc_count = 0;
|
||||
async->buf_write_count = 0;
|
||||
async->buf_read_alloc_count = 0;
|
||||
@ -241,18 +243,20 @@ void comedi_buf_reset(struct comedi_async *async)
|
||||
async->events = 0;
|
||||
}
|
||||
|
||||
static unsigned int comedi_buf_write_n_available(struct comedi_async *async)
|
||||
static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s)
|
||||
{
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
|
||||
|
||||
return free_end - async->buf_write_alloc_count;
|
||||
}
|
||||
|
||||
static unsigned int __comedi_buf_write_alloc(struct comedi_async *async,
|
||||
static unsigned int __comedi_buf_write_alloc(struct comedi_subdevice *s,
|
||||
unsigned int nbytes,
|
||||
int strict)
|
||||
{
|
||||
unsigned int available = comedi_buf_write_n_available(async);
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int available = comedi_buf_write_n_available(s);
|
||||
|
||||
if (nbytes > available)
|
||||
nbytes = strict ? 0 : available;
|
||||
@ -269,10 +273,10 @@ static unsigned int __comedi_buf_write_alloc(struct comedi_async *async,
|
||||
}
|
||||
|
||||
/* allocates chunk for the writer from free buffer space */
|
||||
unsigned int comedi_buf_write_alloc(struct comedi_async *async,
|
||||
unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s,
|
||||
unsigned int nbytes)
|
||||
{
|
||||
return __comedi_buf_write_alloc(async, nbytes, 0);
|
||||
return __comedi_buf_write_alloc(s, nbytes, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_buf_write_alloc);
|
||||
|
||||
@ -280,10 +284,10 @@ EXPORT_SYMBOL_GPL(comedi_buf_write_alloc);
|
||||
* munging is applied to data by core as it passes between user
|
||||
* and kernel space
|
||||
*/
|
||||
static unsigned int comedi_buf_munge(struct comedi_async *async,
|
||||
static unsigned int comedi_buf_munge(struct comedi_subdevice *s,
|
||||
unsigned int num_bytes)
|
||||
{
|
||||
struct comedi_subdevice *s = async->subdevice;
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int count = 0;
|
||||
const unsigned num_sample_bytes = bytes_per_sample(s);
|
||||
|
||||
@ -323,23 +327,26 @@ static unsigned int comedi_buf_munge(struct comedi_async *async,
|
||||
return count;
|
||||
}
|
||||
|
||||
unsigned int comedi_buf_write_n_allocated(struct comedi_async *async)
|
||||
unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s)
|
||||
{
|
||||
struct comedi_async *async = s->async;
|
||||
|
||||
return async->buf_write_alloc_count - async->buf_write_count;
|
||||
}
|
||||
|
||||
/* transfers a chunk from writer to filled buffer space */
|
||||
unsigned int comedi_buf_write_free(struct comedi_async *async,
|
||||
unsigned int comedi_buf_write_free(struct comedi_subdevice *s,
|
||||
unsigned int nbytes)
|
||||
{
|
||||
unsigned int allocated = comedi_buf_write_n_allocated(async);
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int allocated = comedi_buf_write_n_allocated(s);
|
||||
|
||||
if (nbytes > allocated)
|
||||
nbytes = allocated;
|
||||
|
||||
async->buf_write_count += nbytes;
|
||||
async->buf_write_ptr += nbytes;
|
||||
comedi_buf_munge(async, async->buf_write_count - async->munge_count);
|
||||
comedi_buf_munge(s, async->buf_write_count - async->munge_count);
|
||||
if (async->buf_write_ptr >= async->prealloc_bufsz)
|
||||
async->buf_write_ptr %= async->prealloc_bufsz;
|
||||
|
||||
@ -347,8 +354,9 @@ unsigned int comedi_buf_write_free(struct comedi_async *async,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_buf_write_free);
|
||||
|
||||
unsigned int comedi_buf_read_n_available(struct comedi_async *async)
|
||||
unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s)
|
||||
{
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned num_bytes;
|
||||
|
||||
if (!async)
|
||||
@ -367,9 +375,10 @@ unsigned int comedi_buf_read_n_available(struct comedi_async *async)
|
||||
EXPORT_SYMBOL_GPL(comedi_buf_read_n_available);
|
||||
|
||||
/* allocates a chunk for the reader from filled (and munged) buffer space */
|
||||
unsigned int comedi_buf_read_alloc(struct comedi_async *async,
|
||||
unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s,
|
||||
unsigned int nbytes)
|
||||
{
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int available;
|
||||
|
||||
available = async->munge_count - async->buf_read_alloc_count;
|
||||
@ -394,9 +403,10 @@ static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async)
|
||||
}
|
||||
|
||||
/* transfers control of a chunk from reader to free buffer space */
|
||||
unsigned int comedi_buf_read_free(struct comedi_async *async,
|
||||
unsigned int comedi_buf_read_free(struct comedi_subdevice *s,
|
||||
unsigned int nbytes)
|
||||
{
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int allocated;
|
||||
|
||||
/*
|
||||
@ -416,36 +426,39 @@ 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, unsigned short x)
|
||||
int comedi_buf_put(struct comedi_subdevice *s, unsigned short x)
|
||||
{
|
||||
unsigned int n = __comedi_buf_write_alloc(async, sizeof(short), 1);
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int n = __comedi_buf_write_alloc(s, sizeof(short), 1);
|
||||
|
||||
if (n < sizeof(short)) {
|
||||
async->events |= COMEDI_CB_ERROR;
|
||||
return 0;
|
||||
}
|
||||
*(unsigned short *)(async->prealloc_buf + async->buf_write_ptr) = x;
|
||||
comedi_buf_write_free(async, sizeof(short));
|
||||
comedi_buf_write_free(s, sizeof(short));
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_buf_put);
|
||||
|
||||
int comedi_buf_get(struct comedi_async *async, unsigned short *x)
|
||||
int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x)
|
||||
{
|
||||
unsigned int n = comedi_buf_read_n_available(async);
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int n = comedi_buf_read_n_available(s);
|
||||
|
||||
if (n < sizeof(short))
|
||||
return 0;
|
||||
comedi_buf_read_alloc(async, sizeof(short));
|
||||
comedi_buf_read_alloc(s, sizeof(short));
|
||||
*x = *(unsigned short *)(async->prealloc_buf + async->buf_read_ptr);
|
||||
comedi_buf_read_free(async, sizeof(short));
|
||||
comedi_buf_read_free(s, sizeof(short));
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_buf_get);
|
||||
|
||||
void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
|
||||
void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset,
|
||||
const void *data, unsigned int num_bytes)
|
||||
{
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int write_ptr = async->buf_write_ptr + offset;
|
||||
|
||||
if (write_ptr >= async->prealloc_bufsz)
|
||||
@ -469,10 +482,11 @@ void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_buf_memcpy_to);
|
||||
|
||||
void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
|
||||
void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset,
|
||||
void *dest, unsigned int nbytes)
|
||||
{
|
||||
void *src;
|
||||
struct comedi_async *async = s->async;
|
||||
unsigned int read_ptr = async->buf_read_ptr + offset;
|
||||
|
||||
if (read_ptr >= async->prealloc_bufsz)
|
||||
|
@ -238,9 +238,9 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
|
||||
}
|
||||
|
||||
static int resize_async_buffer(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_async *async, unsigned new_size)
|
||||
struct comedi_subdevice *s, unsigned new_size)
|
||||
{
|
||||
struct comedi_async *async = s->async;
|
||||
int retval;
|
||||
|
||||
if (new_size > async->max_bufsize)
|
||||
@ -251,7 +251,7 @@ static int resize_async_buffer(struct comedi_device *dev,
|
||||
"subdevice is busy, cannot resize buffer\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (comedi_buf_is_mmapped(async)) {
|
||||
if (comedi_buf_is_mmapped(s)) {
|
||||
dev_dbg(dev->class_dev,
|
||||
"subdevice is mmapped, cannot resize buffer\n");
|
||||
return -EBUSY;
|
||||
@ -380,7 +380,7 @@ static ssize_t read_buffer_kb_store(struct device *csdev,
|
||||
mutex_lock(&dev->mutex);
|
||||
s = comedi_read_subdevice(dev, minor);
|
||||
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
|
||||
err = resize_async_buffer(dev, s, s->async, size);
|
||||
err = resize_async_buffer(dev, s, size);
|
||||
else
|
||||
err = -EINVAL;
|
||||
mutex_unlock(&dev->mutex);
|
||||
@ -493,7 +493,7 @@ static ssize_t write_buffer_kb_store(struct device *csdev,
|
||||
mutex_lock(&dev->mutex);
|
||||
s = comedi_write_subdevice(dev, minor);
|
||||
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
|
||||
err = resize_async_buffer(dev, s, s->async, size);
|
||||
err = resize_async_buffer(dev, s, size);
|
||||
else
|
||||
err = -EINVAL;
|
||||
mutex_unlock(&dev->mutex);
|
||||
@ -583,7 +583,7 @@ static void do_become_nonbusy(struct comedi_device *dev,
|
||||
|
||||
comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
|
||||
if (async) {
|
||||
comedi_buf_reset(async);
|
||||
comedi_buf_reset(s);
|
||||
async->inttrig = NULL;
|
||||
kfree(async->cmd.chanlist);
|
||||
async->cmd.chanlist = NULL;
|
||||
@ -635,7 +635,7 @@ static int is_device_busy(struct comedi_device *dev)
|
||||
s = &dev->subdevices[i];
|
||||
if (s->busy)
|
||||
return 1;
|
||||
if (s->async && comedi_buf_is_mmapped(s->async))
|
||||
if (s->async && comedi_buf_is_mmapped(s))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -668,6 +668,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
|
||||
return -EBUSY;
|
||||
if (dev->attached) {
|
||||
struct module *driver_module = dev->driver->module;
|
||||
|
||||
comedi_device_detach(dev);
|
||||
module_put(driver_module);
|
||||
}
|
||||
@ -740,7 +741,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev,
|
||||
}
|
||||
|
||||
if (bc.size) {
|
||||
retval = resize_async_buffer(dev, s, async, bc.size);
|
||||
retval = resize_async_buffer(dev, s, bc.size);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
}
|
||||
@ -992,8 +993,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
|
||||
return -EACCES;
|
||||
|
||||
if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
|
||||
bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
|
||||
comedi_buf_read_free(async, bi.bytes_read);
|
||||
bi.bytes_read = comedi_buf_read_alloc(s, bi.bytes_read);
|
||||
comedi_buf_read_free(s, bi.bytes_read);
|
||||
|
||||
if (comedi_is_subdevice_idle(s) &&
|
||||
async->buf_write_count == async->buf_read_count) {
|
||||
@ -1003,8 +1004,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
|
||||
|
||||
if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
|
||||
bi.bytes_written =
|
||||
comedi_buf_write_alloc(async, bi.bytes_written);
|
||||
comedi_buf_write_free(async, bi.bytes_written);
|
||||
comedi_buf_write_alloc(s, bi.bytes_written);
|
||||
comedi_buf_write_free(s, bi.bytes_written);
|
||||
}
|
||||
|
||||
copyback_position:
|
||||
@ -1435,13 +1436,15 @@ static int __comedi_get_user_cmd(struct comedi_device *dev,
|
||||
s = &dev->subdevices[cmd->subdev];
|
||||
|
||||
if (s->type == COMEDI_SUBD_UNUSED) {
|
||||
dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd->subdev);
|
||||
dev_dbg(dev->class_dev, "%d not valid subdevice\n",
|
||||
cmd->subdev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!s->do_cmd || !s->do_cmdtest || !s->async) {
|
||||
dev_dbg(dev->class_dev,
|
||||
"subdevice %d does not support commands\n", cmd->subdev);
|
||||
"subdevice %d does not support commands\n",
|
||||
cmd->subdev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1554,7 +1557,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
comedi_buf_reset(async);
|
||||
comedi_buf_reset(s);
|
||||
|
||||
async->cb_mask =
|
||||
COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
|
||||
@ -1597,7 +1600,6 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
|
||||
{
|
||||
struct comedi_cmd cmd;
|
||||
struct comedi_subdevice *s;
|
||||
unsigned int *chanlist = NULL;
|
||||
unsigned int __user *user_chanlist;
|
||||
int ret;
|
||||
|
||||
@ -1626,8 +1628,6 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
kfree(chanlist);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2029,18 +2029,18 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
|
||||
if (s && s->async) {
|
||||
poll_wait(file, &s->async->wait_head, wait);
|
||||
if (!s->busy || !comedi_is_subdevice_running(s) ||
|
||||
comedi_buf_read_n_available(s->async) > 0)
|
||||
comedi_buf_read_n_available(s) > 0)
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
}
|
||||
|
||||
s = comedi_write_subdevice(dev, minor);
|
||||
if (s && s->async) {
|
||||
unsigned int bps = bytes_per_sample(s->async->subdevice);
|
||||
unsigned int bps = bytes_per_sample(s);
|
||||
|
||||
poll_wait(file, &s->async->wait_head, wait);
|
||||
comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
|
||||
comedi_buf_write_alloc(s, s->async->prealloc_bufsz);
|
||||
if (!s->busy || !comedi_is_subdevice_running(s) ||
|
||||
comedi_buf_write_n_allocated(s->async) >= bps)
|
||||
comedi_buf_write_n_allocated(s) >= bps)
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
}
|
||||
|
||||
@ -2136,9 +2136,9 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
|
||||
m = n;
|
||||
if (async->buf_write_ptr + m > async->prealloc_bufsz)
|
||||
m = async->prealloc_bufsz - async->buf_write_ptr;
|
||||
comedi_buf_write_alloc(async, async->prealloc_bufsz);
|
||||
if (m > comedi_buf_write_n_allocated(async))
|
||||
m = comedi_buf_write_n_allocated(async);
|
||||
comedi_buf_write_alloc(s, async->prealloc_bufsz);
|
||||
if (m > comedi_buf_write_n_allocated(s))
|
||||
m = comedi_buf_write_n_allocated(s);
|
||||
if (m < n)
|
||||
n = m;
|
||||
|
||||
@ -2167,7 +2167,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
|
||||
n -= m;
|
||||
retval = -EFAULT;
|
||||
}
|
||||
comedi_buf_write_free(async, n);
|
||||
comedi_buf_write_free(s, n);
|
||||
|
||||
count += n;
|
||||
nbytes -= n;
|
||||
@ -2229,7 +2229,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
|
||||
|
||||
n = nbytes;
|
||||
|
||||
m = comedi_buf_read_n_available(async);
|
||||
m = comedi_buf_read_n_available(s);
|
||||
/* printk("%d available\n",m); */
|
||||
if (async->buf_read_ptr + m > async->prealloc_bufsz)
|
||||
m = async->prealloc_bufsz - async->buf_read_ptr;
|
||||
@ -2272,8 +2272,8 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
|
||||
retval = -EFAULT;
|
||||
}
|
||||
|
||||
comedi_buf_read_alloc(async, n);
|
||||
comedi_buf_read_free(async, n);
|
||||
comedi_buf_read_alloc(s, n);
|
||||
comedi_buf_read_free(s, n);
|
||||
|
||||
count += n;
|
||||
nbytes -= n;
|
||||
@ -2327,46 +2327,12 @@ static int comedi_open(struct inode *inode, struct file *file)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* This is slightly hacky, but we want module autoloading
|
||||
* to work for root.
|
||||
* case: user opens device, attached -> ok
|
||||
* case: user opens device, unattached, !in_request_module -> autoload
|
||||
* case: user opens device, unattached, in_request_module -> fail
|
||||
* case: root opens device, attached -> ok
|
||||
* case: root opens device, unattached, in_request_module -> ok
|
||||
* (typically called from modprobe)
|
||||
* case: root opens device, unattached, !in_request_module -> autoload
|
||||
*
|
||||
* The last could be changed to "-> ok", which would deny root
|
||||
* autoloading.
|
||||
*/
|
||||
mutex_lock(&dev->mutex);
|
||||
if (dev->attached)
|
||||
goto ok;
|
||||
if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
|
||||
dev_dbg(dev->class_dev, "in request module\n");
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
if (capable(CAP_NET_ADMIN) && dev->in_request_module)
|
||||
goto ok;
|
||||
|
||||
dev->in_request_module = true;
|
||||
|
||||
#ifdef CONFIG_KMOD
|
||||
mutex_unlock(&dev->mutex);
|
||||
request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
|
||||
mutex_lock(&dev->mutex);
|
||||
#endif
|
||||
|
||||
dev->in_request_module = false;
|
||||
|
||||
if (!dev->attached && !capable(CAP_NET_ADMIN)) {
|
||||
dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n");
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
ok:
|
||||
if (dev->attached && dev->use_count == 0) {
|
||||
if (!try_module_get(dev->driver->module)) {
|
||||
rc = -ENOSYS;
|
||||
@ -2654,6 +2620,7 @@ static int __init comedi_init(void)
|
||||
/* create devices files for legacy/manual use */
|
||||
for (i = 0; i < comedi_num_legacy_minors; i++) {
|
||||
struct comedi_device *dev;
|
||||
|
||||
dev = comedi_alloc_board_minor(NULL);
|
||||
if (IS_ERR(dev)) {
|
||||
comedi_cleanup_board_minors();
|
||||
|
@ -15,13 +15,13 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s);
|
||||
|
||||
int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
unsigned long new_size);
|
||||
void comedi_buf_reset(struct comedi_async *async);
|
||||
bool comedi_buf_is_mmapped(struct comedi_async *async);
|
||||
void comedi_buf_reset(struct comedi_subdevice *s);
|
||||
bool comedi_buf_is_mmapped(struct comedi_subdevice *s);
|
||||
void comedi_buf_map_get(struct comedi_buf_map *bm);
|
||||
int comedi_buf_map_put(struct comedi_buf_map *bm);
|
||||
struct comedi_buf_map *comedi_buf_map_from_subdev_get(
|
||||
struct comedi_subdevice *s);
|
||||
unsigned int comedi_buf_write_n_allocated(struct comedi_async *async);
|
||||
unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s);
|
||||
void comedi_device_cancel_all(struct comedi_device *dev);
|
||||
|
||||
extern unsigned int comedi_default_buf_size_kb;
|
||||
|
@ -108,8 +108,6 @@ struct comedi_buf_map {
|
||||
};
|
||||
|
||||
struct comedi_async {
|
||||
struct comedi_subdevice *subdevice;
|
||||
|
||||
void *prealloc_buf; /* pre-allocated buffer */
|
||||
unsigned int prealloc_bufsz; /* buffer size, in bytes */
|
||||
struct comedi_buf_map *buf_map; /* map of buffer pages */
|
||||
@ -182,7 +180,6 @@ struct comedi_device {
|
||||
const char *board_name;
|
||||
const void *board_ptr;
|
||||
bool attached:1;
|
||||
bool in_request_module:1;
|
||||
bool ioenabled:1;
|
||||
spinlock_t spinlock;
|
||||
struct mutex mutex;
|
||||
@ -336,19 +333,19 @@ static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd)
|
||||
*/
|
||||
int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev);
|
||||
|
||||
unsigned int comedi_buf_write_alloc(struct comedi_async *, unsigned int);
|
||||
unsigned int comedi_buf_write_free(struct comedi_async *, unsigned int);
|
||||
unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, unsigned int n);
|
||||
unsigned int comedi_buf_write_free(struct comedi_subdevice *s, unsigned int n);
|
||||
|
||||
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);
|
||||
unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s);
|
||||
unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, unsigned int n);
|
||||
unsigned int comedi_buf_read_free(struct comedi_subdevice *s, unsigned int n);
|
||||
|
||||
int comedi_buf_put(struct comedi_async *, unsigned short);
|
||||
int comedi_buf_get(struct comedi_async *, unsigned short *);
|
||||
int comedi_buf_put(struct comedi_subdevice *s, unsigned short x);
|
||||
int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x);
|
||||
|
||||
void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
|
||||
void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset,
|
||||
const void *source, unsigned int num_bytes);
|
||||
void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
|
||||
void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset,
|
||||
void *destination, unsigned int num_bytes);
|
||||
|
||||
/* drivers.c - general comedi driver functions */
|
||||
|
@ -258,6 +258,7 @@ static int insn_rw_emulate_bits(struct comedi_device *dev,
|
||||
const unsigned base_bitfield_channel =
|
||||
(chan < channels_per_bitfield) ? 0 : chan;
|
||||
unsigned int new_data[2];
|
||||
|
||||
memset(new_data, 0, sizeof(new_data));
|
||||
memset(&new_insn, 0, sizeof(new_insn));
|
||||
new_insn.insn = INSN_BITS;
|
||||
@ -306,7 +307,6 @@ static int __comedi_device_postconfig_async(struct comedi_device *dev,
|
||||
return -ENOMEM;
|
||||
|
||||
init_waitqueue_head(&async->wait_head);
|
||||
async->subdevice = s;
|
||||
s->async = async;
|
||||
|
||||
async->max_bufsize = comedi_default_buf_maxsize_kb * 1024;
|
||||
|
@ -30,106 +30,11 @@
|
||||
#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,
|
||||
unsigned int *d1,
|
||||
unsigned int *d2,
|
||||
unsigned int *nanosec,
|
||||
int round_mode)
|
||||
{
|
||||
int divider;
|
||||
int div1, div2;
|
||||
int div1_glb, div2_glb, ns_glb;
|
||||
int div1_lub, div2_lub, ns_lub;
|
||||
int ns;
|
||||
|
||||
divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base;
|
||||
|
||||
/* find 2 integers 1<={x,y}<=65536 such that x*y is
|
||||
close to divider */
|
||||
|
||||
div1_lub = div2_lub = 0;
|
||||
div1_glb = div2_glb = 0;
|
||||
|
||||
ns_glb = 0;
|
||||
ns_lub = 0xffffffff;
|
||||
|
||||
div2 = 0x10000;
|
||||
for (div1 = divider / 65536 + 1; div1 < div2; div1++) {
|
||||
div2 = divider / div1;
|
||||
|
||||
ns = i8253_osc_base * div1 * div2;
|
||||
if (ns <= *nanosec && ns > ns_glb) {
|
||||
ns_glb = ns;
|
||||
div1_glb = div1;
|
||||
div2_glb = div2;
|
||||
}
|
||||
|
||||
div2++;
|
||||
if (div2 <= 65536) {
|
||||
ns = i8253_osc_base * div1 * div2;
|
||||
if (ns > *nanosec && ns < ns_lub) {
|
||||
ns_lub = ns;
|
||||
div1_lub = div1;
|
||||
div2_lub = div2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*nanosec = div1_lub * div2_lub * i8253_osc_base;
|
||||
*d1 = div1_lub & 0xffff;
|
||||
*d2 = div2_lub & 0xffff;
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base,
|
||||
unsigned int *d1,
|
||||
unsigned int *d2,
|
||||
unsigned int *nanosec,
|
||||
int round_mode)
|
||||
{
|
||||
int div1, div2;
|
||||
int base;
|
||||
|
||||
for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) {
|
||||
base = i8253_osc_base * div1;
|
||||
round_mode &= TRIG_ROUND_MASK;
|
||||
switch (round_mode) {
|
||||
case TRIG_ROUND_NEAREST:
|
||||
default:
|
||||
div2 = (*nanosec + base / 2) / base;
|
||||
break;
|
||||
case TRIG_ROUND_DOWN:
|
||||
div2 = (*nanosec) / base;
|
||||
break;
|
||||
case TRIG_ROUND_UP:
|
||||
div2 = (*nanosec + base - 1) / base;
|
||||
break;
|
||||
}
|
||||
if (div2 < 2)
|
||||
div2 = 2;
|
||||
if (div2 <= 65536) {
|
||||
*nanosec = div2 * base;
|
||||
*d1 = div1 & 0xffff;
|
||||
*d2 = div2 & 0xffff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* shouldn't get here */
|
||||
div1 = 0x10000;
|
||||
div2 = 0x10000;
|
||||
*nanosec = div1 * div2 * i8253_osc_base;
|
||||
*d1 = div1 & 0xffff;
|
||||
*d2 = div2 & 0xffff;
|
||||
}
|
||||
|
||||
static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base,
|
||||
unsigned int *d1,
|
||||
unsigned int *d2,
|
||||
unsigned int *nanosec,
|
||||
int round_mode)
|
||||
static inline void i8253_cascade_ns_to_timer(int i8253_osc_base,
|
||||
unsigned int *d1,
|
||||
unsigned int *d2,
|
||||
unsigned int *nanosec,
|
||||
int round_mode)
|
||||
{
|
||||
unsigned int divider;
|
||||
unsigned int div1, div2;
|
||||
@ -386,7 +291,7 @@ static inline int i8254_set_mode(unsigned long base_address,
|
||||
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
if (mode > (I8254_MODE5 | I8254_BINARY))
|
||||
if (mode > (I8254_MODE5 | I8254_BCD))
|
||||
return -1;
|
||||
|
||||
byte = counter_number << 6;
|
||||
@ -406,7 +311,7 @@ static inline int i8254_mm_set_mode(void __iomem *base_address,
|
||||
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
if (mode > (I8254_MODE5 | I8254_BINARY))
|
||||
if (mode > (I8254_MODE5 | I8254_BCD))
|
||||
return -1;
|
||||
|
||||
byte = counter_number << 6;
|
||||
|
@ -117,7 +117,7 @@ void subdev_8255_interrupt(struct comedi_device *dev,
|
||||
d = spriv->io(0, _8255_DATA, 0, iobase);
|
||||
d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
|
||||
|
||||
comedi_buf_put(s->async, d);
|
||||
comedi_buf_put(s, d);
|
||||
s->async->events |= COMEDI_CB_EOS;
|
||||
|
||||
comedi_event(dev, s);
|
||||
@ -231,7 +231,7 @@ static int subdev_8255_cmdtest(struct comedi_device *dev,
|
||||
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->scan_end_arg, cmd->chanlist_len);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
|
||||
|
||||
if (err)
|
||||
@ -298,6 +298,7 @@ int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
s->len_chanlist = 1;
|
||||
s->do_cmdtest = subdev_8255_cmdtest;
|
||||
s->do_cmd = subdev_8255_cmd;
|
||||
s->cancel = subdev_8255_cancel;
|
||||
|
@ -22,10 +22,10 @@
|
||||
#include "../comedidev.h"
|
||||
|
||||
int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
int (*io) (int, int, int, unsigned long),
|
||||
int (*io)(int, int, int, unsigned long),
|
||||
unsigned long iobase);
|
||||
int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
int (*io) (int, int, int, unsigned long),
|
||||
int (*io)(int, int, int, unsigned long),
|
||||
unsigned long iobase);
|
||||
void subdev_8255_interrupt(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s);
|
||||
|
@ -118,18 +118,10 @@ struct addi_private {
|
||||
int i_IobaseAmcc; /* base+size for AMCC chip */
|
||||
int i_IobaseAddon; /* addon base address */
|
||||
int i_IobaseReserved;
|
||||
unsigned char b_AiContinuous; /* we do unlimited AI */
|
||||
unsigned int ui_AiActualScan; /* how many scans we finished */
|
||||
unsigned int ui_AiNbrofChannels; /* how many channels is measured */
|
||||
unsigned int ui_AiScanLength; /* Length of actual scanlist */
|
||||
unsigned int *pui_AiChannelList; /* actual chanlist */
|
||||
unsigned int ui_AiChannelList[32]; /* actual chanlist */
|
||||
unsigned int ui_AiReadData[32];
|
||||
unsigned int ui_AiTimer0; /* Timer Constant for Timer0 */
|
||||
unsigned int ui_AiTimer1; /* Timer constant for Timer1 */
|
||||
unsigned int ui_AiFlags;
|
||||
unsigned int ui_AiDataLength;
|
||||
unsigned int ui_AiNbrofScans; /* number of scans to do */
|
||||
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 */
|
||||
@ -145,7 +137,7 @@ struct addi_private {
|
||||
unsigned short us_OutputRegister; /* Contain data written at iobase + 0 */
|
||||
unsigned char b_Timer2Mode; /* Specify the timer 2 mode */
|
||||
unsigned char b_Timer2Interrupt; /* Timer2 interrupt enable or disable */
|
||||
unsigned char b_AiCyclicAcquisition; /* indicate cyclic acquisition */
|
||||
unsigned int ai_running:1;
|
||||
unsigned char b_InterruptMode; /* eoc eos or dma */
|
||||
unsigned char b_EocEosInterrupt; /* Enable disable eoc eos interrupt */
|
||||
unsigned int ui_EocEosConversionTime;
|
||||
|
@ -21,6 +21,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../addi_watchdog.h"
|
||||
|
||||
#define APCI1564_ADDRESS_RANGE 128
|
||||
|
||||
/* Digital Input IRQ Function Selection */
|
||||
@ -76,7 +78,7 @@
|
||||
#define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64
|
||||
|
||||
/*
|
||||
* devpriv->iobase Register Map
|
||||
* dev>iobase Register Map
|
||||
*/
|
||||
#define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20))
|
||||
#define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20))
|
||||
@ -127,18 +129,6 @@ static int apci1564_di_config(struct comedi_device *dev,
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int apci1564_di_insn_bits(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct addi_private *devpriv = dev->private;
|
||||
|
||||
data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DI_REG);
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures The Digital Output Subdevice.
|
||||
*
|
||||
@ -180,23 +170,6 @@ static int apci1564_do_config(struct comedi_device *dev,
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int apci1564_do_insn_bits(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct addi_private *devpriv = dev->private;
|
||||
|
||||
s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DO_REG);
|
||||
|
||||
if (comedi_dio_update_state(s, data))
|
||||
outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DO_REG);
|
||||
|
||||
data[1] = s->state;
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures The Timer, Counter or Watchdog
|
||||
*
|
||||
@ -239,13 +212,13 @@ static int apci1564_timer_config(struct comedi_device *dev,
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG);
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_IRQ_REG);
|
||||
outl(0x0,
|
||||
devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1));
|
||||
dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1));
|
||||
outl(0x0,
|
||||
devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2));
|
||||
dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2));
|
||||
outl(0x0,
|
||||
devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3));
|
||||
dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3));
|
||||
outl(0x0,
|
||||
devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4));
|
||||
dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4));
|
||||
} else {
|
||||
/* disable Timer interrupt */
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
|
||||
@ -266,13 +239,13 @@ static int apci1564_timer_config(struct comedi_device *dev,
|
||||
devpriv->b_ModeSelectRegister = data[5];
|
||||
|
||||
/* First Stop The Counter */
|
||||
ul_Command1 = inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
ul_Command1 = inl(dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
|
||||
/* Stop The Timer */
|
||||
outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
|
||||
/* Set the reload value */
|
||||
outl(data[3], devpriv->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1));
|
||||
outl(data[3], dev->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1));
|
||||
|
||||
/* Set the mode : */
|
||||
/* - Disable the hardware */
|
||||
@ -285,15 +258,15 @@ static int apci1564_timer_config(struct comedi_device *dev,
|
||||
ul_Command1 =
|
||||
(ul_Command1 & 0xFFFC19E2UL) | 0x80000UL |
|
||||
(unsigned int) ((unsigned int) data[4] << 16UL);
|
||||
outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
|
||||
/* Enable or Disable Interrupt */
|
||||
ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1);
|
||||
outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
|
||||
/* Set the Up/Down selection */
|
||||
ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18);
|
||||
outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
|
||||
} else {
|
||||
dev_err(dev->class_dev, "Invalid subdevice.\n");
|
||||
}
|
||||
@ -349,8 +322,8 @@ static int apci1564_timer_write(struct comedi_device *dev,
|
||||
}
|
||||
if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
|
||||
ul_Command1 =
|
||||
inl(devpriv->iobase +
|
||||
APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1));
|
||||
inl(dev->iobase +
|
||||
APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1));
|
||||
if (data[1] == 1) {
|
||||
/* Start the Counter subdevice */
|
||||
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
|
||||
@ -362,9 +335,8 @@ static int apci1564_timer_write(struct comedi_device *dev,
|
||||
/* Clears the Counter subdevice */
|
||||
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400;
|
||||
}
|
||||
outl(ul_Command1,
|
||||
devpriv->iobase +
|
||||
APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1));
|
||||
outl(ul_Command1, dev->iobase +
|
||||
APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1));
|
||||
}
|
||||
return insn->n;
|
||||
}
|
||||
@ -393,11 +365,11 @@ static int apci1564_timer_read(struct comedi_device *dev,
|
||||
} else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
|
||||
/* Read the Counter Actual Value. */
|
||||
data[0] =
|
||||
inl(devpriv->iobase +
|
||||
APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1));
|
||||
inl(dev->iobase +
|
||||
APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1));
|
||||
ul_Command1 =
|
||||
inl(devpriv->iobase +
|
||||
APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1));
|
||||
inl(dev->iobase +
|
||||
APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1));
|
||||
|
||||
/* Get the software trigger status */
|
||||
data[1] = (unsigned char) ((ul_Command1 >> 1) & 1);
|
||||
@ -446,13 +418,13 @@ static void apci1564_interrupt(int irq, void *d)
|
||||
ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG) & 0x01;
|
||||
ui_Timer = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_IRQ_REG) & 0x01;
|
||||
ui_C1 =
|
||||
inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1;
|
||||
inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1;
|
||||
ui_C2 =
|
||||
inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1;
|
||||
inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1;
|
||||
ui_C3 =
|
||||
inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1;
|
||||
inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1;
|
||||
ui_C4 =
|
||||
inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1;
|
||||
inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1;
|
||||
if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0
|
||||
&& ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) {
|
||||
dev_err(dev->class_dev, "Interrupt from unknown source.\n");
|
||||
@ -506,16 +478,16 @@ static void apci1564_interrupt(int irq, void *d)
|
||||
|
||||
/* Disable Counter Interrupt */
|
||||
ul_Command2 =
|
||||
inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
|
||||
inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
|
||||
outl(0x0,
|
||||
devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
|
||||
dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
|
||||
|
||||
/* Send a signal to from kernel to user space */
|
||||
send_sig(SIGIO, devpriv->tsk_Current, 0);
|
||||
|
||||
/* Enable Counter Interrupt */
|
||||
outl(ul_Command2,
|
||||
devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
|
||||
dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,16 +497,16 @@ static void apci1564_interrupt(int irq, void *d)
|
||||
|
||||
/* Disable Counter Interrupt */
|
||||
ul_Command2 =
|
||||
inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
|
||||
inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
|
||||
outl(0x0,
|
||||
devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
|
||||
dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
|
||||
|
||||
/* Send a signal to from kernel to user space */
|
||||
send_sig(SIGIO, devpriv->tsk_Current, 0);
|
||||
|
||||
/* Enable Counter Interrupt */
|
||||
outl(ul_Command2,
|
||||
devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
|
||||
dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,16 +516,16 @@ static void apci1564_interrupt(int irq, void *d)
|
||||
|
||||
/* Disable Counter Interrupt */
|
||||
ul_Command2 =
|
||||
inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
|
||||
inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
|
||||
outl(0x0,
|
||||
devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
|
||||
dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
|
||||
|
||||
/* Send a signal to from kernel to user space */
|
||||
send_sig(SIGIO, devpriv->tsk_Current, 0);
|
||||
|
||||
/* Enable Counter Interrupt */
|
||||
outl(ul_Command2,
|
||||
devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
|
||||
dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,45 +535,17 @@ static void apci1564_interrupt(int irq, void *d)
|
||||
|
||||
/* Disable Counter Interrupt */
|
||||
ul_Command2 =
|
||||
inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
|
||||
inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
|
||||
outl(0x0,
|
||||
devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
|
||||
dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
|
||||
|
||||
/* Send a signal to from kernel to user space */
|
||||
send_sig(SIGIO, devpriv->tsk_Current, 0);
|
||||
|
||||
/* Enable Counter Interrupt */
|
||||
outl(ul_Command2,
|
||||
devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
|
||||
dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int apci1564_reset(struct comedi_device *dev)
|
||||
{
|
||||
struct addi_private *devpriv = dev->private;
|
||||
|
||||
/* disable the interrupts */
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
|
||||
/* Reset the interrupt status register */
|
||||
inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG);
|
||||
/* Disable the and/or interrupt */
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG);
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG);
|
||||
devpriv->b_DigitalOutputRegister = 0;
|
||||
ui_Type = 0;
|
||||
/* Resets the output channels */
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_REG);
|
||||
/* Disables the interrupt. */
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG);
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_REG);
|
||||
outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
|
||||
|
||||
outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
|
||||
outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
|
||||
outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
|
||||
outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
|
||||
return 0;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user